Candidato: Renato Massamitsu Zama Inomata
Você foi alocado(a) em um time da Indicium que está trabalhando atualmente junto a um cliente que o core business é compra e venda de veículos usados. Essa empresa está com dificuldades na área de revenda dos automóveis usados em seu catálogo.
Para resolver esse problema, a empresa comprou uma base de dados de um marketplace de compra e venda para entender melhor o mercado nacional, de forma a conseguir precificar o seu catálogo de forma mais competitiva e assim recuperar o mau desempenho neste setor.
Seu objetivo é analisar os dados para responder às perguntas de negócios feitas pelo cliente e criar um modelo preditivo que precifique os carros do cliente de forma que eles fiquem o mais próximos dos valores de mercado.
Este notebook contém a etapa referente à EDA do projeto.
O conteúdo será dividido em 5 partes:
I) Introdução, onde importaremos os dados e pacotes necessários, bem como visualizaremos uma pequena porção dos dados;
II) Análise das features, onde faremos uma análise mais minunciosa de cada variável, e também iremos comparar suas relações com a variável target;
III) Perguntas propostas, onde responderemos às perguntas de negócio propostas pela Incidium para este trabalho;
IV) Outras hipóteses, onde criaremos nossas próprias hipóteses e tentaremos respondê-las utilizando os dados disponíveis;
V) Conclusões, onde reuniremos as informações relevantes levantadas acerca do conjunto de dados.
Finalizada a análise exploratória dos dados, espera-se entender as relações entre variáveis, servindo como base para a próxima etapa de Machine Learning, onde aplicaremos técnicas para prever os valores dos veículos.
Começaremos importando os pacotes e dados.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
pd.set_option('display.max_columns', None)
df = pd.read_csv('./dataset/cars_train.csv', sep='\t', encoding='utf_16')
Visualizando os dados:
display(df.head(5))
print(f'Tamanho do dataset: {df.shape}')
| id | num_fotos | marca | modelo | versao | ano_de_fabricacao | ano_modelo | hodometro | cambio | num_portas | tipo | blindado | cor | tipo_vendedor | cidade_vendedor | estado_vendedor | anunciante | entrega_delivery | troca | elegivel_revisao | dono_aceita_troca | veiculo_único_dono | revisoes_concessionaria | ipva_pago | veiculo_licenciado | garantia_de_fábrica | revisoes_dentro_agenda | veiculo_alienado | preco | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 300716223898539419613863097469899222392 | 8.0 | NISSAN | KICKS | 1.6 16V FLEXSTART SL 4P XTRONIC | 2017 | 2017.0 | 67772.0 | CVT | 4 | Sedã | N | Branco | PF | Rio de Janeiro | São Paulo (SP) | Pessoa Física | False | False | False | NaN | NaN | Todas as revisões feitas pela concessionária | IPVA pago | Licenciado | NaN | NaN | NaN | 74732.590084 |
| 1 | 279639842134129588306469566150288644214 | 8.0 | JEEP | COMPASS | 2.0 16V FLEX LIMITED AUTOMÁTICO | 2017 | 2017.0 | 62979.0 | Automática | 4 | Sedã | N | Branco | PF | Belo Horizonte | Minas Gerais (MG) | Pessoa Física | False | False | False | Aceita troca | NaN | NaN | IPVA pago | NaN | NaN | NaN | NaN | 81965.332634 |
| 2 | 56414460810621048900295678236538171981 | 16.0 | KIA | SORENTO | 2.4 16V GASOLINA EX 7L AWD AUTOMÁTICO | 2018 | 2019.0 | 44070.0 | Automática | 4 | Sedã | N | Preto | PJ | Santos | São Paulo (SP) | Loja | True | False | False | Aceita troca | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 162824.814472 |
| 3 | 56862509826849933428086372390159405545 | 14.0 | VOLKSWAGEN | AMAROK | 2.0 HIGHLINE 4X4 CD 16V TURBO INTERCOOLER DIES... | 2013 | 2015.0 | 85357.0 | Automática | 4 | Picape | N | Branco | PJ | Sorocaba | São Paulo (SP) | Loja | True | True | False | Aceita troca | NaN | NaN | IPVA pago | Licenciado | NaN | NaN | NaN | 123681.358857 |
| 4 | 338980975753200343894519909855598027197 | 8.0 | SSANGYONG | KORANDO | 2.0 GLS 4X4 16V TURBO DIESEL 4P AUTOMÁTICO | 2013 | 2015.0 | 71491.0 | Automática | 4 | Utilitário esportivo | N | Preto | PF | Rio de Janeiro | Rio de Janeiro (RJ) | Pessoa Física | False | False | False | NaN | NaN | Todas as revisões feitas pela concessionária | NaN | NaN | Garantia de fábrica | Todas as revisões feitas pela agenda do carro | NaN | 82419.763891 |
Tamanho do dataset: (29584, 29)
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 29584 entries, 0 to 29583 Data columns (total 29 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 id 29584 non-null object 1 num_fotos 29407 non-null float64 2 marca 29584 non-null object 3 modelo 29584 non-null object 4 versao 29584 non-null object 5 ano_de_fabricacao 29584 non-null int64 6 ano_modelo 29584 non-null float64 7 hodometro 29584 non-null float64 8 cambio 29584 non-null object 9 num_portas 29584 non-null int64 10 tipo 29584 non-null object 11 blindado 29584 non-null object 12 cor 29584 non-null object 13 tipo_vendedor 29584 non-null object 14 cidade_vendedor 29584 non-null object 15 estado_vendedor 29584 non-null object 16 anunciante 29584 non-null object 17 entrega_delivery 29584 non-null bool 18 troca 29584 non-null bool 19 elegivel_revisao 29584 non-null bool 20 dono_aceita_troca 21922 non-null object 21 veiculo_único_dono 10423 non-null object 22 revisoes_concessionaria 9172 non-null object 23 ipva_pago 19659 non-null object 24 veiculo_licenciado 15906 non-null object 25 garantia_de_fábrica 4365 non-null object 26 revisoes_dentro_agenda 5910 non-null object 27 veiculo_alienado 0 non-null float64 28 preco 29584 non-null float64 dtypes: bool(3), float64(5), int64(2), object(19) memory usage: 6.0+ MB
Vamos utilizar o método describe para verificarmos as principais estatísticas das variáveis numéricas do conjunto de dados.
Estará sendo apresentado a contagem, a média dos valores, desvio padrão, mínimos, máximos e quartis de 25%, 50% (mediana) e 75%. Essas informações permitem entender de uma forma mais geral como estão distribuídos os valores para cada uma das variáveis.
df.describe().T
| count | mean | std | min | 25% | 50% | 75% | max | |
|---|---|---|---|---|---|---|---|---|
| num_fotos | 29407.0 | 10.323834 | 3.487334 | 8.000000 | 8.000000 | 8.000000 | 14.000000 | 2.100000e+01 |
| ano_de_fabricacao | 29584.0 | 2016.758552 | 4.062422 | 1985.000000 | 2015.000000 | 2018.000000 | 2019.000000 | 2.022000e+03 |
| ano_modelo | 29584.0 | 2017.808985 | 2.673930 | 1997.000000 | 2016.000000 | 2018.000000 | 2020.000000 | 2.023000e+03 |
| hodometro | 29584.0 | 58430.592077 | 32561.769309 | 100.000000 | 31214.000000 | 57434.000000 | 81953.500000 | 3.900650e+05 |
| num_portas | 29584.0 | 3.940677 | 0.338360 | 2.000000 | 4.000000 | 4.000000 | 4.000000 | 4.000000e+00 |
| veiculo_alienado | 0.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| preco | 29584.0 | 133023.879880 | 81662.872247 | 9869.950645 | 76571.768462 | 114355.796998 | 163679.617425 | 1.359813e+06 |
# Verificando se há ids duplicados
df.id.duplicated().sum()
0
A seguir, vamos verificar como estão distribuídas as observações de cada uma das features.
# Funções auxiliares
# Pintar de laranja os maiores valores
def highlight_max(element):
is_max = (element == element.max())
return ['background: darkorange' if cell == True else '' for cell in is_max]
# Pintar de azul os menores valores
def highlight_min(element):
is_min = (element == element.min())
return ['background: royalblue' if cell == True else '' for cell in is_min]
# Agrega o preço pela feature especificada, apresenta algumas estatísticas da feature
def agg_preco(data, feature):
agg_df = data.groupby(feature).agg({'preco': ['count', 'sum', 'mean', 'std', 'min', 'max']}) \
.preco.sort_values('sum', ascending=False).round(2) \
.style.apply(highlight_max).apply(highlight_min)
return agg_df
# num_fotos
print(f'Quantidade de nulos em `num_fotos`: {df.num_fotos.isna().sum()} ({df.num_fotos.isna().sum()/df.shape[0] * 100:.2f}%)')
# Verificando a distribuição de número de fotos
display(
df.num_fotos.value_counts() \
.reset_index().sort_values('index') \
.rename(columns={'index':'num_fotos', 'num_fotos':'quantidade'}).set_index('num_fotos').T
)
Quantidade de nulos em `num_fotos`: 177 (0.60%)
| num_fotos | 8.0 | 9.0 | 10.0 | 11.0 | 12.0 | 13.0 | 14.0 | 15.0 | 16.0 | 17.0 | 18.0 | 19.0 | 20.0 | 21.0 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| quantidade | 19420 | 728 | 3 | 21 | 147 | 717 | 1811 | 2764 | 2227 | 985 | 248 | 45 | 286 | 5 |
Vamos preencher os valores nulos com zeros e aproveitaremos também para trocar o tipo de float para int.
df['num_fotos'] = df.num_fotos.fillna(0).astype(int)
A seguir, estaremos plotando um gráfico de contagem por número de fotos.
# Plotagem do gráfico
plt.figure(figsize=(7, 5))
ax = sns.countplot(df.sort_values('num_fotos'), x='num_fotos', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.ylabel('Contagem')
plt.xlabel('Número de fotos')
plt.title('Contagem por número de fotos')
plt.show()
agg_preco(df, 'num_fotos')
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| num_fotos | ||||||
| 8 | 19420 | 2642130265.090000 | 136052.020000 | 82100.750000 | 9869.950000 | 1154360.170000 |
| 15 | 2764 | 349779964.090000 | 126548.470000 | 83706.720000 | 13642.890000 | 1140112.650000 |
| 16 | 2227 | 284835737.390000 | 127901.090000 | 80310.090000 | 16264.970000 | 676234.220000 |
| 14 | 1811 | 225125529.490000 | 124310.070000 | 73021.060000 | 14011.650000 | 552000.550000 |
| 17 | 985 | 130169389.170000 | 132151.660000 | 92001.800000 | 16283.020000 | 1349747.710000 |
| 9 | 728 | 88645891.870000 | 121766.330000 | 38856.440000 | 29608.910000 | 317452.090000 |
| 13 | 717 | 86682623.760000 | 120896.270000 | 93676.560000 | 21656.420000 | 1359812.890000 |
| 20 | 286 | 48546249.770000 | 169742.130000 | 106116.040000 | 29328.120000 | 660950.460000 |
| 18 | 248 | 31472121.620000 | 126903.720000 | 82111.270000 | 21608.710000 | 642644.310000 |
| 0 | 177 | 20804623.670000 | 117540.250000 | 35033.000000 | 38412.090000 | 194826.940000 |
| 12 | 147 | 17590256.840000 | 119661.610000 | 64282.770000 | 31996.960000 | 378098.320000 |
| 19 | 45 | 5735860.960000 | 127463.580000 | 82366.970000 | 28378.720000 | 468150.890000 |
| 11 | 21 | 2523839.300000 | 120182.820000 | 56924.210000 | 44212.290000 | 279383.630000 |
| 21 | 5 | 1179733.230000 | 235946.650000 | 79037.040000 | 122998.440000 | 343686.480000 |
| 10 | 3 | 156376.130000 | 52125.380000 | 9540.350000 | 43993.870000 | 62627.530000 |
Uma boa ferramenta visual para analisar distribuições é o boxplot, uma vez que permite rapidamente identificar os valores dos quartis e a presença de outliers. O Intervalo Interquartil (IQR) é visualmente representado pelo tamanho das caixas, e nos permite inferir se os dados estão concentrados (quando a caixa é pequena) ou estão mais dispersos (caixa maior).
plt.figure(figsize=(10, 5))
ax = sns.boxplot(df,
x='num_fotos', y='preco')
plt.xlabel('Número de fotos')
plt.ylabel('Preços')
plt.title('Boxplot dos preços por número de fotos')
plt.show()
Vamos realizar uma contagem de veículos vendidos por marca.
# Verificando a quantidade de veículos por marca em uma data frame horizontal
print('Quantidade de veículos vendidos por marca')
display(df.marca.value_counts().to_frame().T.rename(index={'marca': 'quantidade'}))
Quantidade de veículos vendidos por marca
| VOLKSWAGEN | CHEVROLET | TOYOTA | HYUNDAI | JEEP | FIAT | BMW | AUDI | PEUGEOT | HONDA | MERCEDES-BENZ | FORD | MITSUBISHI | LAND ROVER | RENAULT | NISSAN | KIA | PORSCHE | VOLVO | CITROËN | TROLLER | RAM | CHERY | JAGUAR | MINI | LEXUS | SUZUKI | SUBARU | DODGE | CHRYSLER | SSANGYONG | SMART | ALFA ROMEO | LIFAN | MASERATI | JAC | IVECO | EFFA | FERRARI | BRM | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| quantidade | 4594 | 3020 | 2180 | 2043 | 2000 | 1918 | 1784 | 1698 | 1675 | 1586 | 1125 | 1060 | 862 | 760 | 538 | 438 | 408 | 349 | 287 | 194 | 177 | 168 | 153 | 148 | 137 | 75 | 41 | 41 | 37 | 30 | 14 | 12 | 9 | 8 | 7 | 3 | 2 | 1 | 1 | 1 |
# Plotagem do gráfico
plt.figure(figsize=(10, 8))
ax = sns.countplot(df.sort_values('marca'), y='marca', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.xlabel('Número de veículos')
plt.ylabel('Marca')
plt.title('Número de veículos por marca')
plt.show()
print('Top 10 modelos mais vendidos')
display(
df[['marca', 'modelo']].value_counts().to_frame().rename(columns={0: 'quantidade'}).head(10)
)
Top 10 modelos mais vendidos
| quantidade | ||
|---|---|---|
| marca | modelo | |
| JEEP | COMPASS | 1480 |
| PEUGEOT | 2008 | 1431 |
| AUDI | Q3 | 914 |
| FIAT | TORO | 902 |
| TOYOTA | COROLLA | 867 |
| CHEVROLET | ONIX | 855 |
| BMW | 320i | 822 |
| VOLKSWAGEN | AMAROK | 725 |
| GOLF | 697 | |
| TOYOTA | HILUX | 648 |
print('Top 10 marcas com mais modelos diferentes de carros')
display(
df.groupby(['marca']).modelo.nunique().sort_values(ascending=False).to_frame().head(10)
)
Top 10 marcas com mais modelos diferentes de carros
| modelo | |
|---|---|
| marca | |
| MERCEDES-BENZ | 74 |
| BMW | 50 |
| CHEVROLET | 29 |
| VOLKSWAGEN | 27 |
| AUDI | 24 |
| FIAT | 21 |
| HYUNDAI | 17 |
| MITSUBISHI | 16 |
| FORD | 16 |
| RENAULT | 13 |
print('Top 10 modelos com mais versões diferentes')
display(
df.groupby(['marca', 'modelo']).versao.nunique().sort_values(ascending=False).to_frame().head(10)
)
Top 10 modelos com mais versões diferentes
| versao | ||
|---|---|---|
| marca | modelo | |
| FORD | ECOSPORT | 29 |
| RENAULT | SANDERO | 27 |
| HYUNDAI | HB20 | 26 |
| CHEVROLET | ONIX | 25 |
| S10 | 25 | |
| HONDA | CIVIC | 24 |
| AUDI | A3 | 22 |
| FORD | RANGER | 22 |
| VOLKSWAGEN | FOX | 22 |
| FORD | FIESTA | 21 |
Analisando as marcas, modelos e versões com relação ao preço:
# Marca
agg_preco(df, 'marca')
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| marca | ||||||
| VOLKSWAGEN | 4594 | 541816761.430000 | 117940.090000 | 64307.660000 | 9869.950000 | 771701.880000 |
| BMW | 1784 | 357694116.720000 | 200501.190000 | 93841.350000 | 32086.060000 | 1019840.610000 |
| TOYOTA | 2180 | 340505449.110000 | 156195.160000 | 89191.350000 | 18528.460000 | 781750.380000 |
| CHEVROLET | 3020 | 281426805.570000 | 93187.680000 | 48755.520000 | 16264.970000 | 674366.330000 |
| JEEP | 2000 | 276734332.000000 | 138367.170000 | 48603.310000 | 31229.670000 | 412803.030000 |
| AUDI | 1698 | 271642220.080000 | 159977.750000 | 75142.240000 | 22140.450000 | 672933.090000 |
| PEUGEOT | 1675 | 205686373.770000 | 122797.840000 | 36905.170000 | 11606.400000 | 238684.790000 |
| MERCEDES-BENZ | 1125 | 198979624.010000 | 176870.780000 | 96623.240000 | 27882.010000 | 712798.860000 |
| FIAT | 1918 | 191246013.670000 | 99711.160000 | 46443.020000 | 13642.890000 | 332809.780000 |
| HYUNDAI | 2043 | 172469323.750000 | 84419.640000 | 34553.720000 | 25341.210000 | 361366.800000 |
| LAND ROVER | 760 | 169947539.980000 | 223615.180000 | 110280.310000 | 38663.680000 | 1349747.710000 |
| HONDA | 1586 | 159584454.110000 | 100620.720000 | 42634.130000 | 17197.110000 | 298075.390000 |
| FORD | 1060 | 135100246.000000 | 127453.060000 | 89350.330000 | 17167.430000 | 653173.280000 |
| MITSUBISHI | 862 | 122575786.150000 | 142199.290000 | 89396.620000 | 26041.990000 | 622754.220000 |
| PORSCHE | 349 | 110698376.960000 | 317187.330000 | 155129.380000 | 44462.950000 | 1359812.890000 |
| VOLVO | 287 | 57054984.570000 | 198797.860000 | 95075.050000 | 35778.170000 | 504148.110000 |
| RAM | 168 | 53963008.360000 | 321208.380000 | 104732.780000 | 119950.230000 | 1154360.170000 |
| KIA | 408 | 50287146.800000 | 123252.810000 | 53569.730000 | 26201.310000 | 398170.570000 |
| NISSAN | 438 | 47862589.850000 | 109275.320000 | 58314.810000 | 27584.950000 | 357269.050000 |
| RENAULT | 538 | 44465360.450000 | 82649.370000 | 39557.650000 | 15420.370000 | 258751.800000 |
| JAGUAR | 148 | 32588880.300000 | 220195.140000 | 79554.250000 | 55058.710000 | 436968.980000 |
| TROLLER | 177 | 26297004.490000 | 148570.650000 | 58185.450000 | 45778.290000 | 371164.960000 |
| MINI | 137 | 20033850.400000 | 146232.480000 | 66841.080000 | 40751.850000 | 421457.730000 |
| CHERY | 153 | 18622630.960000 | 121716.540000 | 41468.620000 | 52683.850000 | 238564.340000 |
| CITROËN | 194 | 14257929.830000 | 73494.480000 | 42942.320000 | 19757.200000 | 231444.510000 |
| LEXUS | 75 | 13870383.730000 | 184938.450000 | 58913.530000 | 21815.220000 | 327694.770000 |
| SUBARU | 41 | 5669191.030000 | 138272.950000 | 92903.050000 | 36700.200000 | 404233.180000 |
| SUZUKI | 41 | 3796795.830000 | 92604.780000 | 40169.970000 | 26834.820000 | 192079.280000 |
| DODGE | 37 | 2751714.670000 | 74370.670000 | 25801.570000 | 29085.540000 | 132105.440000 |
| CHRYSLER | 30 | 1877093.540000 | 62569.780000 | 24651.040000 | 28811.810000 | 120719.760000 |
| MASERATI | 7 | 1513038.730000 | 216148.390000 | 154917.040000 | 48954.380000 | 442765.730000 |
| SSANGYONG | 14 | 1189750.850000 | 84982.200000 | 47249.730000 | 37234.110000 | 170328.510000 |
| SMART | 12 | 1094914.760000 | 91242.900000 | 46812.370000 | 46074.430000 | 169896.350000 |
| LIFAN | 8 | 673293.970000 | 84161.750000 | 31536.590000 | 25195.990000 | 120895.510000 |
| ALFA ROMEO | 9 | 613552.890000 | 68172.540000 | 10404.090000 | 43378.850000 | 79559.600000 |
| IVECO | 2 | 302395.110000 | 151197.560000 | 3537.760000 | 148695.980000 | 153699.130000 |
| JAC | 3 | 283162.860000 | 94387.620000 | 38885.780000 | 64185.140000 | 138263.180000 |
| FERRARI | 1 | 114439.240000 | 114439.240000 | nan | 114439.240000 | 114439.240000 |
| BRM | 1 | 47762.670000 | 47762.670000 | nan | 47762.670000 | 47762.670000 |
| EFFA | 1 | 40163.180000 | 40163.180000 | nan | 40163.180000 | 40163.180000 |
plt.figure(figsize=(15, 10))
ax = sns.barplot(df.groupby('marca').preco.mean().reset_index(), x='preco', y='marca', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.xlabel('Preço')
plt.ylabel('Marca')
plt.title('Média de preços por marca')
plt.show()
print(f'Número de nulos da variável `ano_de_fabricacao`: {df.ano_de_fabricacao.isna().sum()}')
print('-'*64)
print('Top 10 anos com mais veículos vendidos')
display(
df.value_counts('ano_de_fabricacao').head(10)
)
print('-'*64)
print('Venda dos últimos 10 anos')
display(
df.value_counts('ano_de_fabricacao', sort=False).tail(10)
)
Número de nulos da variável `ano_de_fabricacao`: 0 ---------------------------------------------------------------- Top 10 anos com mais veículos vendidos
ano_de_fabricacao 2020 4729 2017 4369 2019 3880 2018 3820 2021 2614 2013 2443 2014 2221 2016 1822 2015 1753 2012 509 dtype: int64
---------------------------------------------------------------- Venda dos últimos 10 anos
ano_de_fabricacao 2013 2443 2014 2221 2015 1753 2016 1822 2017 4369 2018 3820 2019 3880 2020 4729 2021 2614 2022 37 dtype: int64
plt.figure(figsize=(16,9))
ax = sns.countplot(df, x='ano_de_fabricacao', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.ylabel('Contagem')
plt.xlabel('Ano de fabricação')
plt.xticks(rotation=90)
plt.title('Contagem por ano de fabricação')
plt.show()
agg_preco(df, 'ano_de_fabricacao')
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| ano_de_fabricacao | ||||||
| 2020 | 4729 | 702871216.290000 | 148629.990000 | 80156.350000 | 22935.930000 | 486869.600000 |
| 2017 | 4369 | 596779000.210000 | 136593.960000 | 82499.470000 | 16264.970000 | 683272.720000 |
| 2018 | 3820 | 569432874.820000 | 149066.200000 | 88275.740000 | 21414.770000 | 1349747.710000 |
| 2019 | 3880 | 563045159.600000 | 145114.730000 | 81102.230000 | 20759.090000 | 1154360.170000 |
| 2021 | 2614 | 371627144.440000 | 142168.000000 | 75306.890000 | 29678.390000 | 464786.420000 |
| 2013 | 2443 | 267275342.720000 | 109404.560000 | 73571.380000 | 21384.260000 | 739900.310000 |
| 2014 | 2221 | 258745833.110000 | 116499.700000 | 79480.470000 | 18729.070000 | 1359812.890000 |
| 2016 | 1822 | 243685996.460000 | 133746.430000 | 84603.170000 | 29400.900000 | 706087.580000 |
| 2015 | 1753 | 221918619.620000 | 126593.620000 | 78062.650000 | 14011.650000 | 1028431.260000 |
| 2012 | 509 | 49500752.610000 | 97250.990000 | 61747.540000 | 21423.510000 | 674366.330000 |
| 2008 | 117 | 7995735.960000 | 68339.620000 | 27859.070000 | 13642.890000 | 161030.480000 |
| 2007 | 121 | 7181705.360000 | 59352.940000 | 26501.250000 | 21031.790000 | 160157.080000 |
| 2001 | 95 | 5987993.080000 | 63031.510000 | 32279.390000 | 15953.200000 | 164922.900000 |
| 2011 | 75 | 5962924.900000 | 79505.670000 | 39434.680000 | 17911.210000 | 173276.830000 |
| 2009 | 82 | 5679085.840000 | 69257.140000 | 35373.250000 | 14302.710000 | 221455.150000 |
| 2006 | 88 | 5618458.450000 | 63846.120000 | 25717.810000 | 14562.300000 | 152438.340000 |
| 2022 | 37 | 5447768.530000 | 147236.990000 | 75862.710000 | 46892.300000 | 398047.500000 |
| 2010 | 83 | 5068233.360000 | 61063.050000 | 29100.810000 | 19725.190000 | 150396.280000 |
| 1999 | 80 | 4896375.830000 | 61204.700000 | 27404.470000 | 13576.400000 | 145151.970000 |
| 2002 | 80 | 4877276.410000 | 60965.960000 | 30086.360000 | 19906.360000 | 144046.670000 |
| 2000 | 81 | 4667346.870000 | 57621.570000 | 25006.800000 | 17167.430000 | 174045.760000 |
| 2003 | 72 | 4195078.980000 | 58264.990000 | 27570.960000 | 15420.370000 | 164807.460000 |
| 2005 | 62 | 4085325.800000 | 65892.350000 | 27886.820000 | 22761.350000 | 139352.430000 |
| 1998 | 66 | 3748555.260000 | 56796.290000 | 24371.870000 | 11606.400000 | 121421.180000 |
| 1997 | 61 | 3455310.460000 | 56644.430000 | 29922.490000 | 14464.690000 | 181941.380000 |
| 2004 | 55 | 3085940.240000 | 56108.000000 | 24261.810000 | 18525.080000 | 159002.210000 |
| 1996 | 58 | 3075549.110000 | 53026.710000 | 22597.240000 | 18544.760000 | 125309.700000 |
| 1995 | 34 | 1673936.680000 | 49233.430000 | 21729.330000 | 19026.030000 | 111279.820000 |
| 1994 | 31 | 1647441.720000 | 53143.280000 | 22065.880000 | 18528.460000 | 116814.150000 |
| 1993 | 15 | 688283.830000 | 45885.590000 | 28013.300000 | 20161.920000 | 115237.420000 |
| 1992 | 14 | 675311.010000 | 48236.500000 | 27808.780000 | 9869.950000 | 116786.260000 |
| 1991 | 10 | 535913.580000 | 53591.360000 | 23103.290000 | 23276.850000 | 101472.930000 |
| 1990 | 4 | 171481.460000 | 42870.360000 | 34480.500000 | 16782.040000 | 93421.290000 |
| 1988 | 2 | 52969.680000 | 26484.840000 | 3381.400000 | 24093.830000 | 28875.850000 |
| 1985 | 1 | 22520.070000 | 22520.070000 | nan | 22520.070000 | 22520.070000 |
plt.figure(figsize=(16, 5))
ax = sns.boxplot(df, x='ano_de_fabricacao', y='preco')
plt.xlabel('Ano de fabricação')
plt.xticks(rotation=90)
plt.ylabel('Preço')
plt.title('Boxplot dos preços por ano de fabricação')
plt.show()
Se acompanharmos a linha da mediana dos boxplots podemos verificar que, em geral, carros de 2012 para 2022 estão vendendo por preços maiores.
Em média, carros fabricados em 2022 têm o preço de R$ 147.2 mil, enquanto que carros de 2012 custam R$ 97.3 mil, que é aproximadamente 33% menor que os carros mais novos.
print(f'Número de nulos: {df.ano_modelo.isna().sum()}')
print('-'*64)
print('Top 10 anos com mais veículos vendidos')
display(
df.value_counts('ano_modelo').head(10)
)
print('-'*64)
print('Vendas dos 10 últimos anos')
display(
df.value_counts('ano_modelo', sort=False).tail(10)
)
Número de nulos: 0 ---------------------------------------------------------------- Top 10 anos com mais veículos vendidos
ano_modelo 2021.0 5071 2017.0 4519 2018.0 4221 2019.0 3587 2020.0 3541 2015.0 2386 2014.0 2377 2013.0 1212 2016.0 890 2022.0 829 dtype: int64
---------------------------------------------------------------- Vendas dos 10 últimos anos
ano_modelo 2014.0 2377 2015.0 2386 2016.0 890 2017.0 4519 2018.0 4221 2019.0 3587 2020.0 3541 2021.0 5071 2022.0 829 2023.0 15 dtype: int64
Vamos realizar um tratamento para transformar a variável de float para int.
df['ano_modelo'] = df.ano_modelo.astype(int)
plt.figure(figsize=(8, 5))
ax = sns.countplot(df, x='ano_modelo', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.ylabel('Contagem')
plt.xlabel('Ano do modelo')
plt.xticks(rotation=90)
plt.title('Contagem por ano do modelo')
plt.show()
agg_preco(df, 'ano_modelo')
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| ano_modelo | ||||||
| 2021 | 5071 | 721183775.130000 | 142217.270000 | 74798.620000 | 22935.930000 | 486869.600000 |
| 2017 | 4519 | 618773193.660000 | 136927.020000 | 82572.450000 | 16264.970000 | 1359812.890000 |
| 2018 | 4221 | 601078087.080000 | 142401.820000 | 86826.030000 | 21991.000000 | 966844.650000 |
| 2020 | 3541 | 535906034.830000 | 151343.130000 | 83385.130000 | 20759.090000 | 1154360.170000 |
| 2019 | 3587 | 533304218.190000 | 148676.950000 | 86553.090000 | 21414.770000 | 1349747.710000 |
| 2015 | 2386 | 276897932.500000 | 116051.100000 | 66479.560000 | 14011.650000 | 1028431.260000 |
| 2014 | 2377 | 268347009.890000 | 112893.150000 | 86487.280000 | 20452.090000 | 739900.310000 |
| 2016 | 890 | 114467881.260000 | 128615.600000 | 83912.490000 | 16289.990000 | 706087.580000 |
| 2022 | 829 | 111852267.610000 | 134924.330000 | 70696.550000 | 29678.390000 | 464786.420000 |
| 2013 | 1212 | 92879838.720000 | 76633.530000 | 41239.090000 | 13576.400000 | 446797.420000 |
| 2012 | 693 | 45689255.010000 | 65929.660000 | 34120.380000 | 9869.950000 | 288821.320000 |
| 2011 | 228 | 12449988.700000 | 54605.210000 | 25420.170000 | 14562.300000 | 159002.210000 |
| 2023 | 15 | 1542939.950000 | 102862.660000 | 33429.220000 | 62591.620000 | 188324.150000 |
| 2010 | 9 | 535091.900000 | 59454.660000 | 43356.520000 | 16782.040000 | 161030.480000 |
| 2008 | 4 | 324037.030000 | 81009.260000 | 37613.230000 | 58607.620000 | 137292.420000 |
| 1997 | 1 | 93842.540000 | 93842.540000 | nan | 93842.540000 | 93842.540000 |
| 2006 | 1 | 53068.360000 | 53068.360000 | nan | 53068.360000 | 53068.360000 |
plt.figure(figsize=(10, 5))
sns.boxplot(df, x='ano_modelo', y='preco')
plt.xlabel('Ano modelo')
plt.ylabel('Preço')
plt.title('Boxplot de preços por ano modelo')
plt.show()
Curiosamente, esperava-se que veículos com ano modelo mais recente teriam preços maiores que veículos mais antigos, porém essa relação não fica bastante explícita uma vez que os carros de 2020 aparentam ser mais caros que os demais.
Além disso, há algum tipo de inconsistência: o menor ano do modelo é 1997 enquanto que o de fabricação é 1988. Vamos verificar:
# Selecionando apenas os veículos que possuem ano de fabricacao menor que 1997
df[df.ano_de_fabricacao < 1997].sort_values('ano_de_fabricacao').head()
| id | num_fotos | marca | modelo | versao | ano_de_fabricacao | ano_modelo | hodometro | cambio | num_portas | tipo | blindado | cor | tipo_vendedor | cidade_vendedor | estado_vendedor | anunciante | entrega_delivery | troca | elegivel_revisao | dono_aceita_troca | veiculo_único_dono | revisoes_concessionaria | ipva_pago | veiculo_licenciado | garantia_de_fábrica | revisoes_dentro_agenda | veiculo_alienado | preco | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 590 | 317058348344627599337634039380150700902 | 8 | VOLKSWAGEN | GOL | 1.6 MI POWER 8V FLEX 4P MANUAL G.III | 1985 | 2013 | 192182.0 | Manual | 4 | Sedã | N | Prata | PF | Pomerode | Rio Grande do Sul (RS) | Pessoa Física | False | False | False | NaN | NaN | NaN | IPVA pago | Licenciado | NaN | NaN | NaN | 22520.067767 |
| 13276 | 51936966583809049009169550364057097722 | 8 | PEUGEOT | 307 | 2.0 GRIFFE 16V GASOLINA 4P AUTOMÁTICO | 1988 | 2011 | 163780.0 | Automática | 4 | Hatchback | N | Prata | PF | Muzambinho | Rio Grande do Sul (RS) | Pessoa Física | False | False | False | NaN | NaN | Todas as revisões feitas pela concessionária | IPVA pago | NaN | NaN | Todas as revisões feitas pela agenda do carro | NaN | 24093.833734 |
| 19658 | 64369313258166945961672474305820655846 | 8 | VOLKSWAGEN | FUSCA | 1.6 8V GASOLINA 2P MANUAL | 1988 | 2011 | 3548.0 | Manual | 4 | Perua/SW | N | Prata | PF | Rio de Janeiro | São Paulo (SP) | Pessoa Física | False | False | False | NaN | NaN | NaN | IPVA pago | NaN | NaN | NaN | NaN | 28875.849751 |
| 20366 | 122284606262184123093871909474981352865 | 8 | LAND ROVER | DISCOVERY 3 | 2.7 HSE 4X4 V6 24V TURBO DIESEL 4P AUTOMÁTICO | 1990 | 2012 | 106774.0 | Automática | 4 | Sedã | N | Preto | PF | São Caetano do Sul | São Paulo (SP) | Pessoa Física | False | False | False | Aceita troca | NaN | Todas as revisões feitas pela concessionária | IPVA pago | Licenciado | NaN | NaN | NaN | 93421.288023 |
| 1156 | 120618350228284858326813530052157947976 | 16 | FIAT | PALIO | 1.3 MPI FIRE ELX WEEKEND 8V FLEX 4P MANUAL | 1990 | 2013 | 171889.0 | Manual | 4 | Hatchback | N | Prata | PJ | Ribeirão Pires | São Paulo (SP) | Loja | True | True | False | Aceita troca | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 26669.839995 |
Pelo apresentado acima, temos um Fusca fabricado em 1988 e modelo 2011 e um Gol Flex fabricado em 1985, antes mesmo do primeiro carro flex.
Percebe-se que exitem algumas inconsistências neste conjunto de dados. Seria interessante comparar qual a diferença em anos entre fabricação e modelo de cada veículo:
# Diferença entre o ano_modelo e ano_de_fabricacao
df['diferenca_ano'] = df.ano_modelo - df.ano_de_fabricacao
display(
df.value_counts('diferenca_ano').sort_index()
)
diferenca_ano 0 12119 1 14177 2 1767 3 334 4 130 5 119 6 88 7 71 8 62 9 63 10 78 11 80 12 87 13 82 14 68 15 69 16 58 17 40 18 36 19 18 20 15 21 11 22 7 23 4 28 1 dtype: int64
Neste link é informado que as negociações de veículo são feitas pelo ano modelo. Contudo, podem haver avaliações de veículos que sejam menores quando os modelos são de "duas cabeças", ou seja, quando são produzidas em um ano e o modelo de outro.
agg_preco(df, 'diferenca_ano')
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| diferenca_ano | ||||||
| 1 | 14177 | 1910755072.440000 | 134778.520000 | 79523.790000 | 16289.990000 | 1349747.710000 |
| 0 | 12119 | 1702727993.800000 | 140500.700000 | 85418.910000 | 14011.650000 | 1140112.650000 |
| 2 | 1767 | 208972520.340000 | 118264.020000 | 66121.310000 | 17911.210000 | 674366.330000 |
| 3 | 334 | 39996785.200000 | 119750.850000 | 96850.200000 | 21639.390000 | 1359812.890000 |
| 4 | 130 | 10286253.990000 | 79125.030000 | 47633.770000 | 13642.890000 | 298571.480000 |
| 5 | 119 | 7652507.370000 | 64306.780000 | 25925.310000 | 14562.300000 | 153921.760000 |
| 6 | 88 | 5655331.420000 | 64265.130000 | 28540.680000 | 25553.690000 | 160157.080000 |
| 12 | 87 | 5171982.010000 | 59448.070000 | 32154.320000 | 16283.020000 | 174045.760000 |
| 11 | 80 | 5074810.510000 | 63435.130000 | 28410.770000 | 15953.200000 | 149952.930000 |
| 10 | 78 | 4763809.040000 | 61074.470000 | 28519.620000 | 19906.360000 | 164807.460000 |
| 13 | 82 | 4724216.430000 | 57612.400000 | 25483.810000 | 17720.560000 | 150181.930000 |
| 7 | 71 | 4271747.090000 | 60165.450000 | 27945.210000 | 18525.080000 | 159002.210000 |
| 15 | 69 | 4255992.090000 | 61681.040000 | 28517.200000 | 14464.690000 | 134619.530000 |
| 14 | 68 | 3842995.430000 | 56514.640000 | 25548.500000 | 11606.400000 | 145151.970000 |
| 8 | 62 | 3784749.400000 | 61044.350000 | 24963.690000 | 15420.370000 | 124013.340000 |
| 9 | 63 | 3648061.260000 | 57905.730000 | 26031.750000 | 22140.450000 | 140291.430000 |
| 16 | 58 | 3018818.280000 | 52048.590000 | 20730.260000 | 18544.760000 | 119400.350000 |
| 17 | 40 | 2227222.210000 | 55680.560000 | 31072.120000 | 18528.460000 | 181941.380000 |
| 18 | 36 | 1694484.790000 | 47069.020000 | 20635.980000 | 20161.920000 | 116814.150000 |
| 19 | 18 | 863994.000000 | 47999.670000 | 18611.100000 | 24047.310000 | 98399.710000 |
| 20 | 15 | 809916.260000 | 53994.420000 | 32951.350000 | 9869.950000 | 115237.420000 |
| 21 | 11 | 603681.520000 | 54880.140000 | 25578.360000 | 26805.100000 | 116786.260000 |
| 22 | 7 | 438749.610000 | 62678.520000 | 25764.390000 | 34948.740000 | 101472.930000 |
| 23 | 4 | 114247.810000 | 28561.950000 | 4479.610000 | 24093.830000 | 34608.280000 |
| 28 | 1 | 22520.070000 | 22520.070000 | nan | 22520.070000 | 22520.070000 |
Como esperado, quanto maior a diferença entre anos menor o preço do carro. Talvez a feature diferenca_ano criada possa ser útil na etapa de Machine Learning.
A empresa que recebeu este conjunto de dados precisaria realizar uma investigação mais a fundo sobre essa diferença entre ano modelo e ano fabricação. A princípio estaremos mantendo essas informações, mas seria ao menos interessante compatibilizar as versões dos carros com seus respectivos anos modelos.
Para visualizar a feature hodometro, vamos plotar um histograma, que irá apresentar a contagem de vendas dos veículos para um determinado intervalo de hodometro.
# Valores de hodômetro
plt.figure(figsize=(7, 5))
sns.histplot(df, x='hodometro')
plt.xlabel('Hodômetro')
plt.ylabel('Contagem')
# plt.xticks(np.arange(0, 400000, 20_000))
plt.minorticks_on()
plt.title('Histograma para varíavel `hodometro`')
plt.show()
Percebe-se que os valores se concentram mais à esquerda do gráfico, com dois picos aparentes: um para aproximadamente aproximadamente 3.000 km, e outro para aproximadamente 8.000 km.
plt.figure(figsize=(7, 5))
sns.boxplot(df, y='hodometro')
plt.ylabel('Hodômetro')
plt.title('Boxplot para varíavel `hodometro`')
plt.show()
# Verificando os outliers do hodômetro
df.sort_values('hodometro', ascending=False).head(5)
| id | num_fotos | marca | modelo | versao | ano_de_fabricacao | ano_modelo | hodometro | cambio | num_portas | tipo | blindado | cor | tipo_vendedor | cidade_vendedor | estado_vendedor | anunciante | entrega_delivery | troca | elegivel_revisao | dono_aceita_troca | veiculo_único_dono | revisoes_concessionaria | ipva_pago | veiculo_licenciado | garantia_de_fábrica | revisoes_dentro_agenda | veiculo_alienado | preco | diferenca_ano | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 19895 | 126955414445370751127432133125076302039 | 8 | FORD | TRANSIT | 2.4 FURGÃO LONGO TURBO DIESEL 3P MANUAL | 2001 | 2012 | 390065.0 | Manual | 2 | Picape | N | Branco | PF | Campinas | São Paulo (SP) | Pessoa Física | False | False | False | Aceita troca | NaN | NaN | IPVA pago | Licenciado | NaN | NaN | NaN | 122236.968801 | 11 |
| 591 | 176459444870073105374190357587524594057 | 8 | FIAT | COUPÉ | 2.0 16V GASOLINA 2P MANUAL | 1997 | 2012 | 379155.0 | Manual | 2 | Picape | N | Prata | PF | Santos | São Paulo (SP) | Pessoa Física | False | False | False | Aceita troca | NaN | NaN | IPVA pago | Licenciado | NaN | NaN | NaN | 45647.183036 | 15 |
| 4960 | 255524433019265656171123303995467059480 | 8 | FORD | RANGER | 2.8 XLT LIMITED 4X4 CD 8V TURBO INTERCOOLER DI... | 1991 | 2013 | 376712.0 | Manual | 2 | Picape | N | Prata | PF | São Paulo | São Paulo (SP) | Pessoa Física | False | False | False | Aceita troca | NaN | Todas as revisões feitas pela concessionária | IPVA pago | Licenciado | NaN | Todas as revisões feitas pela agenda do carro | NaN | 66526.753957 | 22 |
| 25466 | 266733556249083435259295458504902452434 | 8 | FORD | RANGER | 4.0 STX 4X2 CE V6 12V GASOLINA 2P MANUAL | 1994 | 2012 | 309465.0 | Manual | 2 | Picape | N | Prata | PF | Serraria | Rio de Janeiro (RJ) | Pessoa Física | False | False | False | Aceita troca | NaN | NaN | IPVA pago | NaN | NaN | NaN | NaN | 47107.361433 | 18 |
| 25256 | 264844634239316365552041657795969597881 | 8 | MERCEDES-BENZ | C 180 | 1.8 CLASSIC PLUS GASOLINA 4P AUTOMÁTICO | 1999 | 2014 | 237288.0 | Automática | 4 | Sedã | N | Preto | PF | Guarulhos | São Paulo (SP) | Pessoa Física | False | False | False | NaN | NaN | NaN | IPVA pago | Licenciado | NaN | NaN | NaN | 30932.412728 | 15 |
Vamos tentar também relacionar os valores de hodômetro com os preços, plotando também uma linha de regressão para avaliar o comportamento dos dados.
plt.figure(figsize=(7, 5))
sns.regplot(df, x='hodometro', y='preco', line_kws={'color':'red'})
plt.xlabel('Hodômetro')
plt.ylabel('Preço')
plt.title('Relação Hodômetro x Preço com linha de regressão linear')
plt.show()
Esperava-se que um valor maior no hodômetro implicaria num menor valor do preço, e essa relação pode ser verificada pela linha vermelha que está decrescendo.
Vamos verificar como se distribuem os dados quando aplicamos log10 aos valores do hodômetro.
plt.figure(figsize=(7, 5))
sns.histplot(x=df['hodometro'].apply(np.log10))
plt.xlabel('Log10(Hodômetro)')
plt.ylabel('Contagem')
plt.title('Histograma para `log10(hodometro)`')
plt.show()
plt.figure(figsize=(7, 5))
sns.regplot(x=df['hodometro'].apply(np.log10), y=df['preco'], line_kws={'color':'red'})
plt.xlabel('Log10(Hodômetro)')
plt.ylabel('Preço')
plt.title('Relação Log10(Hodômetro) x Preço com linha de regressão linear')
plt.show()
# Variável `cambio`
# Número de nulos
print(f'Número de nulos na variável cambio: {df.cambio.isna().sum()}')
display(
df.value_counts('cambio').to_frame().rename(columns={0: 'quantidade'}).T
)
plt.figure(figsize=(12, 5))
ax = sns.countplot(df.sort_values('cambio'), x='cambio', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.ylabel('Contagem')
plt.xlabel('Câmbio')
plt.title('Contagem de veículos por tipo de câmbio')
plt.show()
Número de nulos na variável cambio: 0
| cambio | Automática | Manual | CVT | Automatizada | Automatizada DCT | Semi-automática | Automática Sequencial |
|---|---|---|---|---|---|---|---|
| quantidade | 22545 | 4989 | 1792 | 139 | 53 | 41 | 25 |
agg_preco(df, 'cambio')
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| cambio | ||||||
| Automática | 22545 | 3292646638.880000 | 146047.760000 | 84686.120000 | 15953.200000 | 1359812.890000 |
| Manual | 4989 | 402677444.190000 | 80713.060000 | 48535.580000 | 9869.950000 | 1140112.650000 |
| CVT | 1792 | 206487237.200000 | 115227.250000 | 42801.640000 | 21414.770000 | 348983.270000 |
| Automatizada | 139 | 17368936.570000 | 124956.380000 | 94326.840000 | 28954.030000 | 416020.330000 |
| Automatizada DCT | 53 | 10893809.680000 | 205543.580000 | 115358.970000 | 71797.850000 | 564073.940000 |
| Semi-automática | 41 | 3859109.940000 | 94124.630000 | 49601.360000 | 30359.740000 | 232694.310000 |
| Automática Sequencial | 25 | 1445285.920000 | 57811.440000 | 28604.770000 | 22761.350000 | 128081.350000 |
plt.figure(figsize=(10, 5))
sns.boxplot(df, y='cambio', x='preco')
plt.ylabel('Câmbio')
plt.xlabel('Preço')
plt.title('Boxplot dos preços por tipo de câmbio')
plt.xticks(np.arange(0, 1400001, 100000))
plt.grid(True, axis='x')
plt.show()
Como esperado, os valores dos veículos com câmbio manual são menores que os de câmbio automático.
Enquanto as análises estavam sendo realizadas, notei que algumas das versões dos carros apontavam quando o carro era automático. Notei também que alguns deles não condiziam com o câmbio especificado:
df[(df.versao.str.contains('AUTOM')) & (df.cambio.str.contains('Manual'))][['marca', 'modelo', 'versao', 'cambio']]
| marca | modelo | versao | cambio | |
|---|---|---|---|---|
| 19 | CHEVROLET | ONIX | 1.0 TURBO FLEX PLUS PREMIER AUTOMÁTICO | Manual |
| 343 | JEEP | RENEGADE | 1.8 16V FLEX LONGITUDE 4P AUTOMÁTICO | Manual |
| 533 | CHEVROLET | ONIX | 1.0 TURBO FLEX PLUS PREMIER AUTOMÁTICO | Manual |
| 794 | HYUNDAI | HB20 | 1.6 16V FLEX VISION AUTOMÁTICO | Manual |
| 1091 | PEUGEOT | 2008 | 1.6 16V FLEX GRIFFE 4P AUTOMÁTICO | Manual |
| ... | ... | ... | ... | ... |
| 27592 | TOYOTA | HILUX SW4 | 3.0 SRV 4X4 16V TURBO INTERCOOLER DIESEL 4P AU... | Manual |
| 27875 | BMW | M 240i | 3.0 24V TURBO GASOLINA 2P AUTOMÁTICO | Manual |
| 28233 | CHEVROLET | ONIX | 1.0 TURBO FLEX PREMIER AUTOMÁTICO | Manual |
| 28355 | PEUGEOT | 2008 | 1.6 16V FLEX CROSSWAY 4P AUTOMÁTICO | Manual |
| 29484 | CHEVROLET | ONIX | 1.0 TURBO FLEX LT AUTOMÁTICO | Manual |
98 rows × 4 columns
df[(df.versao.str.contains('MANUAL')) & (~df.cambio.str.contains('Manual'))][['marca', 'modelo', 'versao', 'cambio']]
| marca | modelo | versao | cambio | |
|---|---|---|---|---|
| 1050 | FORD | RANGER | 2.5 XLT 4X2 CD 16V FLEX 4P MANUAL | Automática |
| 2666 | FIAT | TORO | 1.8 16V EVO FLEX ENDURANCE MANUAL | Automática |
| 2833 | VOLKSWAGEN | SPACE CROSS | 1.6 MI 8V FLEX 4P MANUAL | Semi-automática |
| 4992 | FIAT | TORO | 1.8 16V EVO FLEX ENDURANCE MANUAL | Automática |
| 5907 | FIAT | TORO | 1.8 16V EVO FLEX ENDURANCE MANUAL | Automática |
| 7106 | MINI | COOPER | 1.6 S JOHN COOPER WORKS 16V TURBO GASOLINA 2P ... | Automática |
| 8178 | HYUNDAI | HB20 | 1.6 COMFORT PLUS 16V FLEX 4P MANUAL | Automática |
| 9169 | FIAT | MOBI | 1.0 EVO FLEX LIKE. MANUAL | Automática |
| 9425 | CHEVROLET | SPIN | 1.8 LTZ 8V FLEX 4P MANUAL | Automática |
| 10320 | FIAT | TORO | 1.8 16V EVO FLEX ENDURANCE MANUAL | Automática |
| 10701 | CHEVROLET | ONIX | 1.0 TURBO FLEX LTZ MANUAL | Automática |
| 11535 | CHEVROLET | ONIX | 1.0 TURBO FLEX LTZ MANUAL | Automática |
| 13545 | MINI | COOPER | 1.6 COUPÉ JOHN COOPER WORKS 16V TURBO GASOLINA... | Automática |
| 13838 | FIAT | PALIO | 1.8 MPI ADVENTURE WEEKEND 16V FLEX 4P MANUAL | Automatizada |
| 14456 | FIAT | TORO | 1.8 16V EVO FLEX ENDURANCE MANUAL | Automática |
| 15405 | MINI | COOPER | 2.0 S EXCLUSIVE 16V TURBO GASOLINA 2P MANUAL | Automática |
| 16910 | FIAT | TORO | 1.8 16V EVO FLEX ENDURANCE MANUAL | Automática |
| 17034 | FIAT | TORO | 1.8 16V EVO FLEX ENDURANCE MANUAL | Automática |
| 17898 | FIAT | TORO | 1.8 16V EVO FLEX ENDURANCE MANUAL | Automática |
| 18027 | MINI | COOPER | 2.0 S EXCLUSIVE 16V TURBO GASOLINA 2P MANUAL | Automática |
| 18333 | FORD | RANGER | 2.5 XLT 4X2 CD 16V FLEX 4P MANUAL | Automática |
| 18365 | FIAT | PALIO | 1.8 MPI ADVENTURE WEEKEND 16V FLEX 4P MANUAL | Automatizada |
| 18515 | CHEVROLET | SPIN | 1.8 LTZ 8V FLEX 4P MANUAL | Automática |
| 19448 | FORD | RANGER | 2.5 XLT 4X2 CD 16V FLEX 4P MANUAL | Automática |
| 19538 | FIAT | TORO | 1.8 16V EVO FLEX ENDURANCE MANUAL | Automática |
| 20048 | FIAT | TORO | 1.8 16V EVO FLEX ENDURANCE MANUAL | Automática |
| 20061 | FIAT | ARGO | 1.8 E.TORQ FLEX HGT MANUAL | Automática |
| 21037 | CHEVROLET | PRISMA | 1.4 MPFI MAXX 8V FLEX 4P MANUAL | Automática |
| 21272 | FORD | ECOSPORT | 1.6 SE 16V FLEX 4P MANUAL | Automática |
| 22862 | FIAT | TORO | 1.8 16V EVO FLEX ENDURANCE MANUAL | Automática |
| 24042 | VOLKSWAGEN | SPACE CROSS | 1.6 MI 8V FLEX 4P MANUAL | Semi-automática |
| 24377 | HYUNDAI | HB20 | 1.0 12V FLEX VISION MANUAL | Automática |
| 24637 | FIAT | TORO | 1.8 16V EVO FLEX ENDURANCE MANUAL | Automática |
| 24717 | FORD | RANGER | 2.5 XLT 4X2 CD 16V FLEX 4P MANUAL | Automática |
| 25044 | FORD | RANGER | 2.5 XLT 4X2 CD 16V FLEX 4P MANUAL | Automática |
| 26467 | FIAT | ARGO | 1.8 E.TORQ FLEX HGT MANUAL | Automática |
| 27049 | FIAT | TORO | 1.8 16V EVO FLEX ENDURANCE MANUAL | Automática |
| 27743 | FIAT | TORO | 1.8 16V EVO FLEX ENDURANCE MANUAL | Automática |
| 28327 | FIAT | TORO | 1.8 16V EVO FLEX ENDURANCE MANUAL | Automática |
| 28465 | FIAT | TORO | 1.8 16V EVO FLEX ENDURANCE MANUAL | Automática |
df1 = df.copy()
# Criando uma coluna nova para substituir a coluna de tipos original
# Verificando quando as substring são encontradas na coluna de versao
automatica = df.versao.str.contains('AUTOM').map({True: 'Automática', False: ''}).to_list()
manual = df.versao.str.contains('MANUAL').map({True: 'Manual', False: ''}).to_list()
# inicializando a lista e concatenando cada uma das listas elemento a elemento
cambios_novos = []
for cambio_autom, cambio_manual, cambio_original in zip(automatica, manual, df.cambio.to_list()):
# Caso alguma das substrings seja encontrada, vamos concatenar ela ao elemento da lista de tipos
if (cambio_autom != '') | (cambio_manual != ''):
cambios_novos.append(cambio_autom + cambio_manual)
# Caso não seja encontrado nenhuma das substrings verificadas acima, adicione o item original da coluna tipo
else:
cambios_novos.append(cambio_original)
cambios_novos
df1['cambio'] = cambios_novos
plt.figure(figsize=(10, 5))
sns.boxplot(df1, y='cambio', x='preco')
plt.ylabel('Câmbio')
plt.xlabel('Preço')
plt.title('Boxplot dos preços por tipo de câmbio')
plt.xticks(np.arange(0, 1400001, 100000))
plt.grid(True, axis='x')
plt.show()
print('Dados originais')
display(
agg_preco(df, 'cambio')
)
print('Dados alterados')
display(
agg_preco(df1, 'cambio')
)
Dados originais
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| cambio | ||||||
| Automática | 22545 | 3292646638.880000 | 146047.760000 | 84686.120000 | 15953.200000 | 1359812.890000 |
| Manual | 4989 | 402677444.190000 | 80713.060000 | 48535.580000 | 9869.950000 | 1140112.650000 |
| CVT | 1792 | 206487237.200000 | 115227.250000 | 42801.640000 | 21414.770000 | 348983.270000 |
| Automatizada | 139 | 17368936.570000 | 124956.380000 | 94326.840000 | 28954.030000 | 416020.330000 |
| Automatizada DCT | 53 | 10893809.680000 | 205543.580000 | 115358.970000 | 71797.850000 | 564073.940000 |
| Semi-automática | 41 | 3859109.940000 | 94124.630000 | 49601.360000 | 30359.740000 | 232694.310000 |
| Automática Sequencial | 25 | 1445285.920000 | 57811.440000 | 28604.770000 | 22761.350000 | 128081.350000 |
Dados alterados
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| cambio | ||||||
| Automática | 23624 | 3402152101.620000 | 144012.530000 | 83802.490000 | 15953.200000 | 1359812.890000 |
| Manual | 4931 | 396162675.160000 | 80341.240000 | 48302.150000 | 9869.950000 | 1140112.650000 |
| CVT | 912 | 117014721.970000 | 128305.620000 | 42163.530000 | 34475.680000 | 283781.750000 |
| Automatizada DCT | 46 | 9722540.550000 | 211359.580000 | 122018.230000 | 71797.850000 | 564073.940000 |
| Automatizada | 58 | 9352823.860000 | 161255.580000 | 103915.320000 | 30407.520000 | 397694.230000 |
| Semi-automática | 6 | 645096.670000 | 107516.110000 | 76086.270000 | 54248.300000 | 232694.310000 |
| Automática Sequencial | 7 | 328502.560000 | 46928.940000 | 24921.850000 | 22761.350000 | 84600.260000 |
# Variável `num_portas`
print(f'Número de nulos na variável `num_portas`: {df.num_portas.isna().sum()}')
display(
df.value_counts('num_portas').to_frame().rename(columns={0: 'quantidade'}).T
)
plt.figure(figsize=(5, 5))
ax = sns.countplot(df.sort_values('num_portas'), x='num_portas', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.ylabel('Contagem')
plt.xlabel('Número de portas')
plt.title('Contagem de veículos por número de portas')
plt.show()
Número de nulos na variável `num_portas`: 0
| num_portas | 4 | 2 | 3 |
|---|---|---|---|
| quantidade | 28697 | 868 | 19 |
# Vamos verificar os carros com 3 portas
df[df.num_portas == 3].head()
| id | num_fotos | marca | modelo | versao | ano_de_fabricacao | ano_modelo | hodometro | cambio | num_portas | tipo | blindado | cor | tipo_vendedor | cidade_vendedor | estado_vendedor | anunciante | entrega_delivery | troca | elegivel_revisao | dono_aceita_troca | veiculo_único_dono | revisoes_concessionaria | ipva_pago | veiculo_licenciado | garantia_de_fábrica | revisoes_dentro_agenda | veiculo_alienado | preco | diferenca_ano | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 734 | 63833503557727963117144856024451837146 | 15 | FIAT | DUCATO | 2.3 MULTIJET DIESEL MAXICARGO MANUAL | 2019 | 2020 | 25359.0 | Manual | 3 | Picape | N | Branco | PJ | São José do Rio Preto | São Paulo (SP) | Loja | True | True | False | Aceita troca | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 163758.616520 | 1 |
| 791 | 52406443374972496219439907843051712946 | 14 | VOLKSWAGEN | SAVEIRO | 1.6 CROSS CE 16V FLEX 2P MANUAL | 2015 | 2016 | 95656.0 | Manual | 3 | Picape | N | Branco | PJ | Guaíba | Rio de Janeiro (RJ) | Loja | True | True | False | Aceita troca | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 125619.258582 | 1 |
| 2047 | 221840944585208773857515626266413117720 | 14 | MERCEDES-BENZ | CLC 200 K | 1.8 KOMPRESSOR 16V GASOLINA 2P AUTOMATICO | 1999 | 2014 | 153909.0 | Automática | 3 | Picape | N | Prata | PJ | Ribeirão Pires | São Paulo (SP) | Loja | True | True | False | Aceita troca | NaN | NaN | IPVA pago | Licenciado | NaN | NaN | NaN | 134619.532624 | 15 |
| 2660 | 209052999009686863855587096190582220393 | 8 | RENAULT | SANDERO | 1.6 16V SCE FLEX STEPWAY MANUAL | 2017 | 2018 | 80189.0 | Manual | 3 | Picape | N | Branco | PJ | Taboão da Serra | São Paulo (SP) | Loja | True | True | False | Aceita troca | Único dono | Todas as revisões feitas pela concessionária | NaN | NaN | NaN | Todas as revisões feitas pela agenda do carro | NaN | 61088.508200 | 1 |
| 4411 | 208623035278673781563602245202263825307 | 13 | TOYOTA | HILUX | 3.0 SRV 4X4 CD 16V TURBO INTERCOOLER DIESEL 4P... | 2014 | 2015 | 89398.0 | Automática | 3 | Picape | N | Branco | PJ | Rio de Janeiro | Rio de Janeiro (RJ) | Loja | True | True | False | Aceita troca | NaN | NaN | IPVA pago | Licenciado | NaN | NaN | NaN | 112589.345348 | 1 |
Apesar de realmente existirem alguns carros com 3 portas, no dataset percebe-se inconsistência, visto que nos nomes das versões temos veículos com 2 portas, uma vez que possuem 2P em sua descrição (ex: 1.6 CROSS CE 16V FLEX 2P MANUAL).
df[df.modelo == 'STRADA'].value_counts(['versao', 'num_portas']).to_frame().reset_index().sort_values('versao').head()
| versao | num_portas | 0 | |
|---|---|---|---|
| 4 | 1.3 FIREFLY FLEX FREEDOM CD MANUAL | 4 | 7 |
| 2 | 1.3 FIREFLY FLEX FREEDOM CS MANUAL | 4 | 39 |
| 10 | 1.3 FIREFLY FLEX FREEDOM CS MANUAL | 2 | 3 |
| 5 | 1.3 FIREFLY FLEX VOLCANO CD MANUAL | 4 | 6 |
| 6 | 1.4 FIRE FLEX ENDURANCE CD MANUAL | 4 | 6 |
Verificando mais de perto, como ilustrado acima, percebe-se que algumas versões estão com números de portas incompatíveis. Aproveitando a análise do número de portas, vale ressaltar que CS, CE e CD nas descrições provavelmente se referem a, respecitvamente, Cabine Simples, Cabine Estendida e Cabine Dupla.
A seguir, vamos verificar como se correlacionam os preços com a variável num_portas.
agg_preco(df, 'num_portas')
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| num_portas | ||||||
| 4 | 28697 | 3786996496.920000 | 131964.890000 | 79639.560000 | 9869.950000 | 1349747.710000 |
| 2 | 868 | 146597926.740000 | 168891.620000 | 127348.330000 | 17720.560000 | 1359812.890000 |
| 3 | 19 | 1784038.720000 | 93896.770000 | 48310.190000 | 26982.470000 | 179691.610000 |
plt.figure(figsize=(10, 5))
sns.boxplot(df, x='num_portas', y='preco')
plt.ylabel('Câmbio')
plt.xlabel('Número de portas')
plt.title('Boxplot dos preços por número de portas')
plt.show()
A seguir, queremos verificar se, para os carros que possuem modelos com diferentes números de portas, existe algum número específico de portas que resulte em valores maiores.
Para isso, vamos selecionar apenas os carros que possuem modelos com diferentes números de portas, calcularemos a mediana e destacamos em verde os maiores valores por modelo.
nportas = df.groupby(['marca', 'modelo', 'num_portas']).agg({'preco': ['median']}).preco.reset_index()
pd.pivot(nportas[nportas.modelo.duplicated(keep=False)], index=['marca', 'modelo'], columns=['num_portas'], values=['median']) \
.style.apply(highlight_max, axis=1)
| median | ||||
|---|---|---|---|---|
| num_portas | 2 | 3 | 4 | |
| marca | modelo | |||
| AUDI | A3 | 311678.464233 | nan | 138227.934992 |
| A5 | 219251.395064 | nan | 208534.639670 | |
| TT | 222843.979264 | nan | 275925.563195 | |
| TT RS | 531828.182741 | nan | 296409.889517 | |
| TTS | 230116.824667 | nan | 406699.181700 | |
| BMW | 428i | 215033.291274 | nan | 181411.094792 |
| 430i | 212188.922368 | nan | 218734.096241 | |
| M 135i | 238743.284426 | nan | 225702.530978 | |
| M 235i | 198678.027363 | nan | 299141.343318 | |
| M 240i | 207648.122907 | nan | 278610.189755 | |
| M2 | 325382.506944 | nan | 331074.053505 | |
| M3 | 188315.122232 | nan | 294766.453459 | |
| Z4 | 271977.422439 | nan | 328755.167251 | |
| CHEVROLET | CAMARO | 216656.309437 | nan | 210157.284319 |
| CORSA | 32229.093534 | nan | 45666.709976 | |
| MONTANA | 72059.399099 | 51710.916072 | 59900.622250 | |
| S10 | 176476.092108 | nan | 147356.659666 | |
| CITROËN | JUMPY | 178242.643976 | nan | 175722.408719 |
| DODGE | DAKOTA | 73384.844768 | nan | 88251.848804 |
| FIAT | DOBLÒ | 163089.395071 | nan | 73900.542387 |
| DUCATO | 133993.069535 | 163758.616520 | 112675.991612 | |
| FIORINO | 124212.560994 | 114683.236482 | 81141.181203 | |
| PALIO | 153647.432417 | nan | 42890.956005 | |
| STRADA | 58426.615991 | 61047.255588 | 67399.125447 | |
| TORO | 124601.775458 | nan | 122802.860936 | |
| FORD | F-1000 | 64628.193405 | nan | 76874.479927 |
| KA | 21031.793774 | nan | 52197.037119 | |
| MUSTANG | 262614.540502 | nan | 289455.984757 | |
| RANGER | 237936.662942 | nan | 181652.067512 | |
| TRANSIT | 122236.968801 | nan | 87551.315805 | |
| HONDA | CIVIC | 207793.208557 | nan | 108633.121716 |
| FIT | 47967.208934 | nan | 74297.267432 | |
| HYUNDAI | HR | 122276.795488 | nan | 152177.839625 |
| KIA | BONGO | 148269.181379 | nan | 138710.694017 |
| CERATO | 111701.592227 | nan | 80544.644176 | |
| SORENTO | 112453.697759 | nan | 120857.810781 | |
| MERCEDES-BENZ | AMG GT | 458765.035247 | nan | 220475.329022 |
| C 180 | 165971.129601 | nan | 152659.200869 | |
| C 250 | 196961.462728 | 161107.732304 | 173627.135024 | |
| C 300 | 221315.860265 | nan | 224757.478863 | |
| C 43 AMG | 332001.464678 | nan | 281634.676919 | |
| CLC 200 K | 89949.326808 | 134619.532624 | nan | |
| CLK 320 | 42385.400654 | nan | 50518.107835 | |
| CLS 350 | 215810.141771 | nan | 290773.546557 | |
| SLC 300 | 349902.927301 | nan | 231086.293811 | |
| SPRINTER | 159165.332925 | 169382.346885 | 175569.574714 | |
| MINI | COOPER | 217524.354433 | nan | 147455.718066 |
| ONE | 84057.567199 | nan | 60253.239254 | |
| MITSUBISHI | ECLIPSE | 95449.383046 | nan | 88205.445629 |
| L200 TRITON | 116033.841820 | nan | 124268.826289 | |
| NISSAN | FRONTIER | 143333.185098 | nan | 155781.379863 |
| PEUGEOT | 307 | 81283.486068 | 91855.504188 | 30209.585392 |
| BOXER | 111771.048882 | nan | 83826.851696 | |
| EXPERT | 198399.319001 | nan | 144589.994122 | |
| PARTNER | 86262.355076 | nan | 112986.799762 | |
| PORSCHE | 718 | 366597.179239 | nan | 369581.779292 |
| 911 | 351034.901428 | nan | 351394.060101 | |
| CAYMAN | 282374.127118 | nan | 97471.222694 | |
| PANAMERA | 111849.828297 | nan | 348014.749244 | |
| RAM | 2500 | 550242.127836 | nan | 321211.235816 |
| RENAULT | DUSTER OROCH | 65372.232608 | 31285.120127 | 86814.570959 |
| KANGOO | 118708.484614 | nan | 90026.696011 | |
| MASTER | 171498.178753 | nan | 146503.775995 | |
| MÉGANE | 85615.508752 | nan | 25204.019133 | |
| SANDERO | nan | 61088.508200 | 57709.078186 | |
| SMART | FORTWO | 151581.170350 | nan | 57096.458102 |
| TOYOTA | HILUX | 144216.946946 | 112589.345348 | 222032.430995 |
| VOLKSWAGEN | AMAROK | 172725.952140 | nan | 165550.601813 |
| FOX | 56971.284901 | nan | 53076.246926 | |
| KOMBI | 44190.570821 | nan | 34948.738336 | |
| NEW BEETLE | 48972.265870 | nan | 43188.106186 | |
| SAVEIRO | 89730.723608 | 125619.258582 | 69443.387314 | |
Pelas observações acima, para os veículos que possuem diferentes números de portas, não fica aparente nenhum tipo de relação entre o número de portas e o preço do veículo.
# Variável `tipo`
# Nulos
print(f'Número de nulos da variável `tipo`: {df.tipo.isna().sum()}')
# Contagem
display(
df.value_counts('tipo').to_frame().T
)
plt.figure(figsize=(10, 5))
ax = sns.countplot(df, x='tipo', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.xlabel('Tipo de veículo')
plt.ylabel('Contagem')
plt.title('Contagem de veículos por tipo')
plt.show()
Número de nulos da variável `tipo`: 0
| tipo | Sedã | Hatchback | Picape | Utilitário esportivo | Perua/SW | Cupê | Minivan |
|---|---|---|---|---|---|---|---|
| 0 | 16429 | 4924 | 4849 | 3322 | 27 | 26 | 7 |
Para um mesmo modelo, parece razóavel termos diferentes tipos, como por exemplo o Ford Ka. Contudo, a mesma versão não deveria ter diferentes tipos, conforme o resultado abaixo:
# Printando o data frame para as colunas com SEDAN
def highlight_sedan(value):
if 'SEDAN' in str(value):
return 'background-color: green'
else:
return ''
df[df.modelo == 'KA'][['marca', 'versao', 'tipo']] \
.sort_values('versao').drop_duplicates() \
.style.applymap(highlight_sedan)
| marca | versao | tipo | |
|---|---|---|---|
| 29409 | FORD | 1.0 MPI 8V FLEX 2P MANUAL | Picape |
| 16305 | FORD | 1.0 MPI 8V FLEX 2P MANUAL | Hatchback |
| 9177 | FORD | 1.0 TI-VCT FLEX SE MANUAL | Picape |
| 9347 | FORD | 1.0 TI-VCT FLEX SE MANUAL | Hatchback |
| 11350 | FORD | 1.0 TI-VCT FLEX SE PLUS MANUAL | Hatchback |
| 2900 | FORD | 1.0 TI-VCT FLEX SE PLUS SEDAN MANUAL | Sedã |
| 18060 | FORD | 1.0 TI-VCT FLEX SE SEDAN MANUAL | Sedã |
| 27653 | FORD | 1.0 TI-VCT FLEX SE SEDAN MANUAL | Hatchback |
| 2862 | FORD | 1.0 TI-VCT FLEX SEL MANUAL | Sedã |
| 16915 | FORD | 1.0 TI-VCT FLEX TECNO MANUAL | Sedã |
| 25921 | FORD | 1.0 TI-VCT FLEX TECNO MANUAL | Hatchback |
| 28054 | FORD | 1.5 SIGMA FLEX SE MANUAL | Hatchback |
| 6031 | FORD | 1.5 SIGMA FLEX SE MANUAL | Picape |
| 26303 | FORD | 1.5 SIGMA FLEX SE PLUS MANUAL | Hatchback |
| 19721 | FORD | 1.5 SIGMA FLEX SEL MANUAL | Picape |
| 27368 | FORD | 1.5 TI-VCT FLEX FREESTYLE AUTOMÁTICO | Hatchback |
| 23403 | FORD | 1.5 TI-VCT FLEX FREESTYLE MANUAL | Hatchback |
| 1816 | FORD | 1.5 TI-VCT FLEX FREESTYLE MANUAL | Sedã |
| 5965 | FORD | 1.5 TI-VCT FLEX SE AUTOMÁTICO | Hatchback |
| 20549 | FORD | 1.5 TI-VCT FLEX SE MANUAL | Hatchback |
| 15574 | FORD | 1.5 TI-VCT FLEX SE PLUS AUTOMÁTICO | Hatchback |
| 2454 | FORD | 1.5 TI-VCT FLEX SE PLUS MANUAL | Hatchback |
| 8023 | FORD | 1.5 TI-VCT FLEX SE PLUS SEDAN AUTOMÁTICO | Sedã |
| 5977 | FORD | 1.5 TI-VCT FLEX SE SEDAN AUTOMÁTICO | Sedã |
| 5868 | FORD | 1.5 TI-VCT FLEX SE SEDAN MANUAL | Sedã |
| 14312 | FORD | 1.5 TI-VCT FLEX TITANIUM SEDAN AUTOMÁTICO | Sedã |
Muito pior, temos alguns carros que estão com a versão Sedan porém com tipo diferente, como Hatchback, neste caso.
# SEDAN
print(f"Número de veículos sedan que não estão classificados corretamente: \
{df[(df.versao.str.contains('SEDAN')) & (df.tipo != 'Sedã')].shape[0]}")
# Data frame
display(
df[(df.versao.str.contains('SEDAN')) & (df.tipo != 'Sedã')][['marca', 'modelo', 'versao', 'tipo']]
)
print('-'*64)
# HATCH
print(f"Número de veículos hatch que não estão classificados corretamente: \
{df[(df.versao.str.contains('HATCH')) & (df.tipo != 'Hatchback')].shape[0]}")
# Data frame
display(
df[(df.versao.str.contains('HATCH')) & (df.tipo != 'Hatchback')][['marca', 'modelo', 'versao', 'tipo']]
)
print('-'*64)
print(f"Número de veículos coupês que não estão classificados corretamente: \
{df[(df.versao.str.contains('COUP')) & (df.tipo != 'Cupê')].shape[0]}")
display(
df[df.versao.str.contains('COUP') & (df.tipo != 'Cupê')][['marca', 'modelo', 'versao', 'tipo']]
)
Número de veículos sedan que não estão classificados corretamente: 112
| marca | modelo | versao | tipo | |
|---|---|---|---|---|
| 366 | AUDI | S3 | 2.0 TFSI SEDAN QUATTRO GASOLINA 4P S-TRONIC | Hatchback |
| 425 | BMW | 535i | 3.0 SEDAN 6 CILINDROS 24V TURBO GASOLINA 4P AU... | Utilitário esportivo |
| 812 | MERCEDES-BENZ | A 200 | 1.3 CGI GASOLINA STYLE SEDAN 7G-DCT | Picape |
| 942 | AUDI | A3 | 2.0 TFSI SEDAN AMBITION 16V GASOLINA 4P S-TRONIC | Hatchback |
| 996 | FORD | FOCUS | 2.0 SE PLUS SEDAN 16V FLEX 4P POWERSHIFT | Utilitário esportivo |
| ... | ... | ... | ... | ... |
| 28547 | MERCEDES-BENZ | C 350 | 3.5 CGI SPORT SEDAN V6 GASOLINA 4P AUTOMÁTICO | Utilitário esportivo |
| 28851 | AUDI | A3 | 2.0 TFSI SEDAN AMBITION 16V GASOLINA 4P S-TRONIC | Hatchback |
| 28944 | AUDI | A3 | 1.4 TFSI SEDAN AMBIENTE 16V FLEX 4P TIPTRONIC | Hatchback |
| 29046 | AUDI | A3 | 2.0 TFSI GASOLINA SEDAN PERFORMANCE BLACK S-TR... | Utilitário esportivo |
| 29555 | BMW | M3 | 3.0 I6 GASOLINA SEDAN AUTOMÁTICO | Hatchback |
112 rows × 4 columns
---------------------------------------------------------------- Número de veículos hatch que não estão classificados corretamente: 9
| marca | modelo | versao | tipo | |
|---|---|---|---|---|
| 1788 | FORD | FIESTA | 1.6 SE HATCH 16V FLEX 4P MANUAL | Sedã |
| 5307 | FORD | FIESTA | 1.5 S HATCH 16V FLEX 4P MANUAL | Picape |
| 10640 | FORD | FIESTA | 1.6 MPI CLASS HATCH 8V FLEX 4P MANUAL | Sedã |
| 14599 | BMW | 120i | 2.0 HATCH 16V GASOLINA 2P AUTOMÁTICO | Picape |
| 14652 | FORD | FIESTA | 1.6 SEL HATCH 16V FLEX 4P POWERSHIFT | Sedã |
| 14751 | CHEVROLET | VECTRA | 2.0 SFI GT HATCH 8V FLEX 4P MANUAL | Perua/SW |
| 16650 | FORD | FIESTA | 1.0 ECOBOOST TITANIUM PLUS HATCH 12V GASOLINA ... | Sedã |
| 17984 | FORD | FIESTA | 1.6 SE STYLE HATCH 16V FLEX 4P MANUAL | Sedã |
| 24180 | BMW | 130i | 3.0 SPORT HATCH 24V GASOLINA 4P AUTOMÁTICO | Picape |
---------------------------------------------------------------- Número de veículos coupês que não estão classificados corretamente: 281
| marca | modelo | versao | tipo | |
|---|---|---|---|---|
| 32 | BMW | X6 | 3.0 35I 4X4 COUPÉ 6 CILINDROS 24V GASOLINA 4P ... | Sedã |
| 395 | AUDI | TT | 2.0 TFSI COUPÉ AMBITION 2P GASOLINA S-TRONIC | Picape |
| 569 | BMW | 218i | 1.5 TWINTURBO GASOLINA GRAN COUPE SPORT GP STE... | Sedã |
| 618 | MERCEDES-BENZ | C 180 | 1.6 CGI GASOLINA AVANTGARDE COUPÉ 9G-TRONIC | Picape |
| 878 | AUDI | TT | 2.0 TFSI COUPÉ AMBITION 2P GASOLINA S-TRONIC | Picape |
| ... | ... | ... | ... | ... |
| 29065 | MERCEDES-BENZ | C 180 | 1.6 CGI GASOLINA SPORT COUPÉ 9G-TRONIC | Picape |
| 29074 | BMW | X6 | 4.4 M SPORT 4X4 COUPÉ V8 32V BI-TURBO GASOLINA... | Sedã |
| 29278 | BMW | M6 | 4.4 GRAN COUPÉ V8 32V GASOLINA 4P AUTOMÁTICO | Hatchback |
| 29498 | MERCEDES-BENZ | GLC 250 | 2.0 CGI GASOLINA COUPÉ 4MATIC 9G-TRONIC | Utilitário esportivo |
| 29516 | BMW | M2 | 3.0 24V I6 GASOLINA COUPÉ M DCT | Picape |
281 rows × 4 columns
Como mencionado na seção num_portas, CS, CE e CD se referem ao tipo de cabine do veículo. É razoável que as picapes apresentem essas siglas no nome de suas versões. Vejamos quais se enquadriam neste caso.
df[df.versao.str.contains(' CS | CD | CE ')][['marca', 'modelo',]].drop_duplicates().sort_values(['marca', 'modelo'])
| marca | modelo | |
|---|---|---|
| 9717 | CHEVROLET | ASTRA |
| 5690 | CHEVROLET | CORSA |
| 19492 | CHEVROLET | D20 |
| 117 | CHEVROLET | MONTANA |
| 1938 | CHEVROLET | OMEGA |
| 190 | CHEVROLET | S10 |
| 9254 | CHEVROLET | SILVERADO |
| 5668 | CHEVROLET | ZAFIRA |
| 4658 | DODGE | DAKOTA |
| 21484 | DODGE | RAM |
| 54 | FIAT | STRADA |
| 1674 | FORD | F-1000 |
| 2552 | FORD | F-250 |
| 107 | FORD | RANGER |
| 3606 | KIA | BONGO |
| 629 | MITSUBISHI | L200 |
| 9340 | MITSUBISHI | L200 OUTDOOR |
| 216 | MITSUBISHI | L200 TRITON |
| 167 | NISSAN | FRONTIER |
| 7159 | RAM | 1500 |
| 351 | RAM | 2500 |
| 105 | TOYOTA | HILUX |
| 3 | VOLKSWAGEN | AMAROK |
| 45 | VOLKSWAGEN | SAVEIRO |
Em uma olhada rápida, os veículos Zafira, Astra e Omega não são picapes:
df[df.modelo.str.contains('ZAFIRA|ASTRA|OMEGA')][['marca', 'modelo', 'versao']].drop_duplicates().sort_values(['marca', 'modelo', 'versao'])
| marca | modelo | versao | |
|---|---|---|---|
| 19386 | CHEVROLET | ASTRA | 1.8 MPFI GL 8V GASOLINA 2P MANUAL |
| 24554 | CHEVROLET | ASTRA | 1.8 MPFI GL SEDAN 8V GASOLINA 4P MANUAL |
| 3021 | CHEVROLET | ASTRA | 2.0 MPFI ADVANTAGE 8V FLEX 4P MANUAL |
| 29048 | CHEVROLET | ASTRA | 2.0 MPFI ADVANTAGE SEDAN 8V FLEX 4P AUTOMÁTICO |
| 6951 | CHEVROLET | ASTRA | 2.0 MPFI ADVANTAGE SEDAN 8V FLEX 4P MANUAL |
| 9717 | CHEVROLET | ASTRA | 2.0 MPFI CD SEDAN 8V GASOLINA 4P AUTOMÁTICO |
| 6868 | CHEVROLET | ASTRA | 2.0 MPFI SPORT 8V GASOLINA 2P MANUAL |
| 1938 | CHEVROLET | OMEGA | 3.6 SFI CD V6 24V GASOLINA 4P AUTOMÁTICO |
| 5668 | CHEVROLET | ZAFIRA | 2.0 MPFI CD 8V GASOLINA 4P AUTOMÁTICO |
| 6547 | CHEVROLET | ZAFIRA | 2.0 MPFI COMFORT 8V FLEX 4P MANUAL |
| 5714 | CHEVROLET | ZAFIRA | 2.0 MPFI ELITE 8V FLEX 4P AUTOMÁTICO |
| 4533 | CHEVROLET | ZAFIRA | 2.0 MPFI EXPRESSION 8V FLEX 4P AUTOMÁTICO |
# Quantidade de veículos por tipo dos veículos que deveriam ser considerados como picapes
df[(df.versao.str.contains(' CS | CD | CE ')) & (df.modelo != 'ZAFIRA') & (df.modelo != 'ASTRA') & (df.modelo != 'OMEGA')]['tipo'].value_counts()
Picape 2655 Hatchback 424 Sedã 127 Cupê 6 Utilitário esportivo 2 Name: tipo, dtype: int64
# Criando uma coluna nova para substituir a coluna de tipos original
# Verificando quando as substring são encontradas na coluna de versao
hatch = df.versao.str.contains('HATCH').map({True: 'Hatchback', False: ''}).to_list()
coupe = df.versao.str.contains('COUP').map({True: 'Cupê', False: ''}).to_list()
sedan = df.versao.str.contains('SEDAN').map({True: 'Sedã', False: ''}).to_list()
picape = ((df.versao.str.contains(' CS | CD | CE ')) & (df.modelo != 'ZAFIRA') & (df.modelo != 'ASTRA') & (df.modelo != 'OMEGA')).map({True: 'Picape', False: ''}).to_list()
# inicializando a lista e concatenando cada uma das listas elemento a elemento
tipos_novos = []
for car_h, car_c, car_s, car_p, tipo in zip(hatch, coupe, sedan, picape, df.tipo.to_list()):
# Caso alguma das substrings seja encontrada, vamos concatenar ela ao elemento da lista de tipos
if (car_h != '') | (car_c != '') | (car_s != '') | (car_p != ''):
tipos_novos.append(car_h + car_c + car_s + car_p )
# Caso não seja encontrado nenhuma das substrings verificadas acima, adicione o item original da coluna tipo
else:
tipos_novos.append(tipo)
tipos_novos
df1['tipo'] = tipos_novos
# No data frame original, verificar apenas as linhas que foram alteradas
display(
df[((df1.tipo == df.tipo) == False)][['marca', 'modelo', 'versao', 'tipo']]
)
print(f'Foram alterados {df[((df1.tipo == df.tipo) == False)].shape[0]} tipos de veículos.')
| marca | modelo | versao | tipo | |
|---|---|---|---|---|
| 32 | BMW | X6 | 3.0 35I 4X4 COUPÉ 6 CILINDROS 24V GASOLINA 4P ... | Sedã |
| 63 | VOLKSWAGEN | AMAROK | 3.0 V6 TDI DIESEL HIGHLINE CD 4MOTION AUTOMÁTICO | Hatchback |
| 117 | CHEVROLET | MONTANA | 1.4 MPFI LS CS 8V FLEX 2P MANUAL | Hatchback |
| 149 | VOLKSWAGEN | AMAROK | 3.0 V6 TDI DIESEL HIGHLINE CD 4MOTION AUTOMÁTICO | Sedã |
| 350 | TOYOTA | HILUX | 2.7 SRV 4X4 CD 16V FLEX 4P AUTOMÁTICO | Hatchback |
| ... | ... | ... | ... | ... |
| 29516 | BMW | M2 | 3.0 24V I6 GASOLINA COUPÉ M DCT | Picape |
| 29526 | CHEVROLET | MONTANA | 1.4 MPFI LS CS 8V FLEX 2P MANUAL | Hatchback |
| 29536 | VOLKSWAGEN | AMAROK | 2.0 HIGHLINE 4X4 CD 16V TURBO INTERCOOLER DIES... | Hatchback |
| 29555 | BMW | M3 | 3.0 I6 GASOLINA SEDAN AUTOMÁTICO | Hatchback |
| 29566 | FIAT | STRADA | 1.3 FIREFLY FLEX FREEDOM CS MANUAL | Hatchback |
961 rows × 4 columns
Foram alterados 961 tipos de veículos.
# Comparando os dados originais e os alterados
print('Dados originais')
display(
agg_preco(df, 'tipo')
)
print('Dados alterados')
display(
agg_preco(df1, 'tipo')
)
Dados originais
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| tipo | ||||||
| Sedã | 16429 | 1941775322.700000 | 118191.940000 | 58672.730000 | 9869.950000 | 711460.360000 |
| Picape | 4849 | 770536216.250000 | 158906.210000 | 101431.040000 | 13642.890000 | 1359812.890000 |
| Utilitário esportivo | 3322 | 751180570.060000 | 226122.990000 | 93074.690000 | 37736.810000 | 1349747.710000 |
| Hatchback | 4924 | 457713457.970000 | 92955.620000 | 55304.900000 | 13576.400000 | 676234.220000 |
| Cupê | 26 | 10744769.350000 | 413260.360000 | 187260.920000 | 141792.180000 | 1019840.610000 |
| Perua/SW | 27 | 2971606.710000 | 110059.510000 | 138245.330000 | 18378.040000 | 660950.460000 |
| Minivan | 7 | 456519.340000 | 65217.050000 | 22929.310000 | 40500.340000 | 93123.280000 |
Dados alterados
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| tipo | ||||||
| Sedã | 16373 | 1925912408.660000 | 117627.340000 | 58358.660000 | 9869.950000 | 711460.360000 |
| Picape | 5251 | 821394285.860000 | 156426.260000 | 99012.900000 | 13642.890000 | 1359812.890000 |
| Utilitário esportivo | 3206 | 720251293.870000 | 224657.300000 | 92358.610000 | 37736.810000 | 1349747.710000 |
| Hatchback | 4425 | 388904039.420000 | 87887.920000 | 49340.010000 | 13576.400000 | 676234.220000 |
| Cupê | 300 | 76218095.170000 | 254060.320000 | 120992.450000 | 18528.460000 | 1019840.610000 |
| Perua/SW | 22 | 2241820.060000 | 101900.910000 | 142616.960000 | 18378.040000 | 660950.460000 |
| Minivan | 7 | 456519.340000 | 65217.050000 | 22929.310000 | 40500.340000 | 93123.280000 |
# Variável `blindado`
# Nulos
print(f'Número de nulos da variável `blindado`: {df.blindado.isna().sum()}')
# Contagem
display(
df.value_counts('blindado').to_frame().T
)
plt.figure(figsize=(5, 5))
ax = sns.countplot(df, x='blindado', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.xlabel('Variável `blindado`')
plt.ylabel('Contagem')
plt.title('Contagem de veículos por variável `blindado`')
plt.show()
Número de nulos da variável `blindado`: 0
| blindado | N | S |
|---|---|---|
| 0 | 29336 | 248 |
Vamos apenas substituir a variável para booleana, onde N: False e S: True.
df['blindado'] = df.blindado.map({'N': False, 'S': True})
agg_preco(df, 'blindado')
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| blindado | ||||||
| False | 29336 | 3883061168.730000 | 132365.050000 | 80800.070000 | 9869.950000 | 1359812.890000 |
| True | 248 | 52317293.650000 | 210956.830000 | 131125.660000 | 37388.930000 | 676721.300000 |
plt.figure(figsize=(5, 5))
sns.boxplot(df, x='blindado', y='preco')
plt.xlabel('É blindado')
plt.ylabel('Preço')
plt.title('Boxplot dos preços dos carros blindados ou não')
plt.show()
Esperava-se que carros blindados fossem mais caros e, em geral, são realmente mais caros.
# Variável `cor`
# Nulos
print(f'Número de nulos da variável `cor`: {df.cor.isna().sum()}')
# Contagem
display(
df.value_counts('cor').to_frame().T
)
Número de nulos da variável `cor`: 0
| cor | Branco | Preto | Prata | Cinza | Dourado | Verde | Vermelho |
|---|---|---|---|---|---|---|---|
| 0 | 20949 | 5256 | 1741 | 1634 | 2 | 1 | 1 |
plt.figure(figsize=(7, 5))
ax = sns.countplot(df, x='cor', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.xlabel('Variável `cor`')
plt.ylabel('Contagem')
plt.title('Contagem de veículos por variável `cor`')
plt.show()
Curiosamente, pouquíssimos carros coloridos.
agg_preco(df, 'cor')
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| cor | ||||||
| Branco | 20949 | 2726714751.770000 | 130159.660000 | 74792.760000 | 14011.650000 | 1359812.890000 |
| Preto | 5256 | 719773724.080000 | 136943.250000 | 103635.890000 | 11606.400000 | 1154360.170000 |
| Cinza | 1634 | 322040446.210000 | 197087.180000 | 82219.850000 | 63561.510000 | 486869.600000 |
| Prata | 1741 | 166555368.020000 | 95666.500000 | 43005.520000 | 9869.950000 | 203786.370000 |
| Dourado | 2 | 177456.720000 | 88728.360000 | 4329.450000 | 85666.980000 | 91789.740000 |
| Verde | 1 | 60668.800000 | 60668.800000 | nan | 60668.800000 | 60668.800000 |
| Vermelho | 1 | 56046.780000 | 56046.780000 | nan | 56046.780000 | 56046.780000 |
plt.figure(figsize=(8, 5))
sns.boxplot(df, x='cor', y='preco', palette=['white', 'dimgray', 'silver', 'darkgray', 'green', 'red', 'gold'])
plt.xlabel('Cor do veículo')
plt.ylabel('Preço')
plt.title('Boxplot dos preços dos carros pela cor')
plt.show()
# Variável `tipo_vendedor`
# Nulos
print(f'Número de nulos da variável `tipo_vendedor`: {df.tipo_vendedor.isna().sum()}')
# Contagem
display(
df.value_counts('tipo_vendedor').to_frame().T
)
Número de nulos da variável `tipo_vendedor`: 0
| tipo_vendedor | PF | PJ |
|---|---|---|
| 0 | 17926 | 11658 |
plt.figure(figsize=(5, 5))
ax = sns.countplot(df, x='tipo_vendedor', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.ylabel('Variável `tipo_vendedor`')
plt.xlabel('Contagem')
plt.title('Contagem de veículos por variável `tipo_vendedor`')
plt.show()
Vamos transformar essa coluna em booleana e para isso renomearemos também a coluna para vendedor_PJ.
df['tipo_vendedor'] = df.tipo_vendedor.map({'PJ': True, 'PF': False})
df.rename(columns={'tipo_vendedor':'vendedor_PJ'}, inplace=True)
agg_preco(df, 'vendedor_PJ')
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| vendedor_PJ | ||||||
| False | 17926 | 2490229755.230000 | 138917.200000 | 84095.570000 | 9869.950000 | 1154360.170000 |
| True | 11658 | 1445148707.150000 | 123961.980000 | 76901.230000 | 13642.890000 | 1359812.890000 |
plt.figure(figsize=(8, 5))
sns.boxplot(df, x='vendedor_PJ', y='preco')
plt.xlabel('Vendedor é PJ?')
plt.ylabel('Preço')
plt.title('Boxplot dos preços dos carros pelo tipo de vendedor')
plt.show()
Esperava-se que vendedores PJ vendessem mais caro que os PFs, porém o contrário ocorreu.
# Variável `cidade_vendedor`
# Nulos
print(f'Número de nulos da variável `cidade_vendedor`: {df.cidade_vendedor.isna().sum()}')
print('-'*64)
print('Top 10 cidades com mais vendas')
display(
df.value_counts('cidade_vendedor').to_frame().head(10)
)
Número de nulos da variável `cidade_vendedor`: 0 ---------------------------------------------------------------- Top 10 cidades com mais vendas
| 0 | |
|---|---|
| cidade_vendedor | |
| São Paulo | 6158 |
| Rio de Janeiro | 5793 |
| Belo Horizonte | 2172 |
| Presidente Prudente | 1536 |
| Goiânia | 1396 |
| Medianeira | 1197 |
| Campinas | 828 |
| São José do Rio Preto | 768 |
| Porto Alegre | 662 |
| Ribeirão Preto | 623 |
# Variável `estado_vendedor`
# Nulos
print(f'Número de nulos da variável `estado_vendedor`: {df.estado_vendedor.isna().sum()}')
print('-'*64)
print('Top 10 estados com mais vendas')
# Contagem
display(
df.value_counts('estado_vendedor').to_frame().head(10)
)
Número de nulos da variável `estado_vendedor`: 0 ---------------------------------------------------------------- Top 10 estados com mais vendas
| 0 | |
|---|---|
| estado_vendedor | |
| São Paulo (SP) | 16378 |
| Rio de Janeiro (RJ) | 2548 |
| Paraná (PR) | 2526 |
| Santa Catarina (SC) | 2302 |
| Minas Gerais (MG) | 1775 |
| Rio Grande do Sul (RS) | 1646 |
| Goiás (GO) | 789 |
| Bahia (BA) | 604 |
| Pernambuco (PE) | 318 |
| Alagoas (AL) | 125 |
plt.figure(figsize=(12, 5))
ax = sns.countplot(df.sort_values('estado_vendedor'), y='estado_vendedor', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.ylabel('Variável `estado_vendedor`')
plt.xlabel('Contagem')
plt.title('Contagem de veículos por variável `estado_vendedor`')
plt.show()
# Agrupando as principais estatísticas por estado
agg_preco(df, 'estado_vendedor')
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| estado_vendedor | ||||||
| São Paulo (SP) | 16378 | 2125155114.630000 | 129756.690000 | 82498.280000 | 11606.400000 | 1154360.170000 |
| Paraná (PR) | 2526 | 367439545.100000 | 145463.000000 | 80845.470000 | 18525.080000 | 643743.120000 |
| Rio de Janeiro (RJ) | 2548 | 343877627.890000 | 134959.820000 | 80460.250000 | 14302.710000 | 683272.720000 |
| Santa Catarina (SC) | 2302 | 309486913.810000 | 134442.620000 | 84432.110000 | 9869.950000 | 1359812.890000 |
| Minas Gerais (MG) | 1775 | 239415444.200000 | 134881.940000 | 76833.900000 | 14464.690000 | 653173.280000 |
| Rio Grande do Sul (RS) | 1646 | 232787858.410000 | 141426.400000 | 82420.790000 | 18394.090000 | 845191.660000 |
| Goiás (GO) | 789 | 121045293.330000 | 153416.090000 | 89247.880000 | 30259.720000 | 1349747.710000 |
| Bahia (BA) | 604 | 78088582.890000 | 129285.730000 | 74953.130000 | 26838.810000 | 466067.890000 |
| Pernambuco (PE) | 318 | 37246223.310000 | 117126.490000 | 62761.800000 | 29624.190000 | 359493.700000 |
| Alagoas (AL) | 125 | 16238319.180000 | 129906.550000 | 65873.670000 | 39477.020000 | 353250.070000 |
| Rio Grande do Norte (RN) | 90 | 10434336.690000 | 115937.070000 | 58463.660000 | 30826.320000 | 349638.430000 |
| Paraíba (PB) | 108 | 10203459.730000 | 94476.480000 | 33659.280000 | 32990.540000 | 214273.680000 |
| Pará (PA) | 74 | 8954652.590000 | 121008.820000 | 42650.620000 | 40905.990000 | 205115.740000 |
| Ceará (CE) | 69 | 7090140.770000 | 102755.660000 | 49326.290000 | 33849.240000 | 274806.840000 |
| Sergipe (SE) | 24 | 5254232.530000 | 218926.360000 | 122743.290000 | 44862.090000 | 464786.420000 |
| Mato Grosso (MT) | 33 | 4728815.870000 | 143297.450000 | 55281.160000 | 59040.520000 | 276335.900000 |
| Amazonas (AM) | 51 | 4337612.420000 | 85051.220000 | 34982.230000 | 22935.930000 | 181175.120000 |
| Mato Grosso do Sul (MS) | 35 | 3964460.970000 | 113270.310000 | 63783.410000 | 40116.950000 | 339355.450000 |
| Acre (AC) | 29 | 2700089.230000 | 93106.530000 | 51962.310000 | 38626.600000 | 228022.080000 |
| Tocantins (TO) | 20 | 2391825.800000 | 119591.290000 | 51096.720000 | 43722.060000 | 243002.220000 |
| Espírito Santo (ES) | 21 | 2027221.850000 | 96534.370000 | 34117.410000 | 48254.680000 | 163579.140000 |
| Piauí (PI) | 6 | 1062716.710000 | 177119.450000 | 57962.430000 | 108140.820000 | 240243.180000 |
| Maranhão (MA) | 7 | 847291.820000 | 121041.690000 | 15134.140000 | 92743.080000 | 137709.160000 |
| Rondônia (RO) | 4 | 473455.280000 | 118363.820000 | 15956.860000 | 94700.110000 | 129613.920000 |
| Roraima (RR) | 2 | 127227.380000 | 63613.690000 | 4208.660000 | 60637.720000 | 66589.670000 |
plt.figure(figsize=(10, 6))
sns.boxplot(df.sort_values('estado_vendedor'), y='estado_vendedor', x='preco', color='lightcoral')
plt.xlabel('Preço')
plt.ylabel('Estado do vendedor')
plt.title('Vendas por estado')
plt.show()
O melhor estado para se comprar um veículo aparentemente seria Roraima, visto que é o estado que em média tem os menores valores. Contudo, esse valor é mascarado pelo fato de que o estado possui apenas duas vendas realizadas.
Dessa maneira, um outro estado que também apresenta veículos mais baratos seria o Amazonas, que efetuou 51 vendas.
De maneira análoga, se fossemos escolher um estado para realizar a venda de um veículo de maneira que o preço seja o maior possível, a escolha seria, pela média, o Sergipe. Contudo, podemos verificar também que é o estado que apresenta o maior desvio padrão, o que indica que os preços de seus veículos estão muito dispersos.
Outras sugestões de estados com preços mais elevados incluem o Mato Grosso e Goiás, que respectivamente tinham as maiores medianas e médias dos preços dos veículos.
agg_preco(df, 'anunciante')
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| anunciante | ||||||
| Pessoa Física | 17999 | 2499610399.850000 | 138874.960000 | 84089.890000 | 9869.950000 | 1154360.170000 |
| Loja | 9879 | 1210197357.240000 | 122502.010000 | 78142.250000 | 13642.890000 | 1359812.890000 |
| Concessionária | 1702 | 225256305.310000 | 132348.010000 | 68477.990000 | 29624.190000 | 563706.680000 |
| Acessórios e serviços para autos | 4 | 314399.980000 | 78599.990000 | 25415.050000 | 42554.540000 | 101221.940000 |
# Variável `anunciante`
# Nulos
print(f'Número de nulos da variável `anunciante`: {df.anunciante.isna().sum()}')
# Contagem
display(
df.value_counts('anunciante').to_frame().T
)
plt.figure(figsize=(10, 5))
ax = sns.countplot(df, x='anunciante', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.xlabel('Variável `anunciante`')
plt.ylabel('Contagem')
plt.title('Contagem de veículos por variável `anunciante`')
plt.show()
Número de nulos da variável `anunciante`: 0
| anunciante | Pessoa Física | Loja | Concessionária | Acessórios e serviços para autos |
|---|---|---|---|---|
| 0 | 17999 | 9879 | 1702 | 4 |
plt.figure(figsize=(5, 5))
ax = sns.histplot(df, x='preco', hue='anunciante')
plt.xlabel('Preço')
plt.ylabel('Contagem')
plt.title('Histograma de preço dos veículos por variável `anunciante`')
plt.show()
plt.figure(figsize=(9, 5))
ax = sns.boxplot(df, y='preco', x='anunciante')
plt.xlabel('Variável `anunciante`')
plt.ylabel('Preço')
plt.title('Boxplot de preço dos veículos por variável `anunciante`')
plt.show()
# Variável `entrega_delivery`
# Nulos
print(f'Número de nulos da variável `entrega_delivery`: {df.entrega_delivery.isna().sum()}')
# Contagem
display(
df.value_counts('entrega_delivery').to_frame().T
)
Número de nulos da variável `entrega_delivery`: 0
| entrega_delivery | False | True |
|---|---|---|
| 0 | 23601 | 5983 |
agg_preco(df, 'entrega_delivery')
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| entrega_delivery | ||||||
| False | 23601 | 3204926326.940000 | 135796.210000 | 81989.520000 | 9869.950000 | 1349747.710000 |
| True | 5983 | 730452135.440000 | 122087.940000 | 79429.870000 | 13642.890000 | 1359812.890000 |
plt.figure(figsize=(5, 5))
ax = sns.countplot(df, x='entrega_delivery', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.xlabel('Variável `entrega_delivery`')
plt.ylabel('Contagem')
plt.title('Contagem de veículos por variável `entrega_delivery`')
plt.show()
plt.figure(figsize=(5, 5))
ax = sns.histplot(df, x='preco', hue='entrega_delivery')
plt.xlabel('Preço')
plt.ylabel('Contagem')
plt.title('Histograma de preço dos veículos por variável `entrega_delivery`')
plt.show()
plt.figure(figsize=(5, 5))
ax = sns.boxplot(df, y='preco', x='entrega_delivery')
plt.xlabel('Variável `entrega_delivery`')
plt.ylabel('Preço')
plt.title('Boxplot de preço dos veículos por variável `entrega_delivery`')
plt.show()
# Variável `troca`
# Nulos
print(f'Número de nulos da variável `troca`: {df.troca.isna().sum()}')
# Contagem
display(
df.value_counts('troca').to_frame().T
)
Número de nulos da variável `troca`: 0
| troca | False | True |
|---|---|---|
| 0 | 24523 | 5061 |
agg_preco(df, 'troca')
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| troca | ||||||
| False | 24523 | 3310765416.530000 | 135006.540000 | 81465.470000 | 9869.950000 | 1349747.710000 |
| True | 5061 | 624613045.850000 | 123416.920000 | 81944.130000 | 13642.890000 | 1359812.890000 |
plt.figure(figsize=(5, 5))
ax = sns.countplot(df, x='troca', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.xlabel('Variável `troca`')
plt.ylabel('Contagem')
plt.title('Contagem de veículos por variável `troca`')
plt.show()
plt.figure(figsize=(5, 5))
ax = sns.histplot(df, x='preco', hue='troca')
plt.xlabel('Preço')
plt.ylabel('Contagem')
plt.title('Histograma de preço dos veículos por variável `troca`')
plt.show()
plt.figure(figsize=(5, 5))
ax = sns.boxplot(df, y='preco', x='troca')
plt.xlabel('Variável `troca`')
plt.ylabel('Preço')
plt.title('Boxplot de preço dos veículos por variável `troca`')
plt.show()
# Variável `elegivel_revisao`
# Nulos
print(f'Número de nulos da variável `elegivel_revisao`: {df.elegivel_revisao.isna().sum()}')
# Contagem
display(
df.value_counts('elegivel_revisao').to_frame().T
)
Número de nulos da variável `elegivel_revisao`: 0
| elegivel_revisao | False |
|---|---|
| 0 | 29584 |
Nenhum veículo estava elegível para revisão.
# Variável `dono_aceita_troca`
# Nulos
print(f'Número de nulos da variável `dono_aceita_troca`: {df.dono_aceita_troca.isna().sum()}')
# Contagem
display(
df.value_counts('dono_aceita_troca').to_frame().T
)
Número de nulos da variável `dono_aceita_troca`: 7662
| dono_aceita_troca | Aceita troca |
|---|---|
| 0 | 21922 |
# Trocando a varíavel para booleana
df['dono_aceita_troca'] = df.dono_aceita_troca.notnull()
agg_preco(df, 'dono_aceita_troca')
| count | sum | mean | std | min | max | |
|---|---|---|---|---|---|---|
| dono_aceita_troca | ||||||
| True | 21922 | 3002096187.940000 | 136944.450000 | 85814.900000 | 9869.950000 | 1359812.890000 |
| False | 7662 | 933282274.450000 | 121806.610000 | 67157.610000 | 11606.400000 | 634313.010000 |
plt.figure(figsize=(5, 5))
ax = sns.countplot(df, x='dono_aceita_troca', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.xlabel('Variável `dono_aceita_troca`')
plt.ylabel('Contagem')
plt.title('Contagem de veículos por variável `dono_aceita_troca`')
plt.show()
plt.figure(figsize=(5, 5))
ax = sns.histplot(df, x='preco', hue='dono_aceita_troca')
plt.xlabel('Preço')
plt.ylabel('Contagem')
plt.title('Histograma de preço dos veículos por variável `dono_aceita_troca`')
plt.show()
plt.figure(figsize=(5, 5))
ax = sns.boxplot(df, y='preco', x='dono_aceita_troca')
plt.xlabel('Variável `dono_aceita_troca`')
plt.ylabel('Preço')
plt.title('Boxplot de preço dos veículos por variável `dono_aceita_troca`')
plt.show()
# Variável `veiculo_único_dono`
# Nulos
print(f'Número de nulos da variável `veiculo_único_dono`: {df.veiculo_único_dono.isna().sum()}')
# Contagem
display(
df.value_counts('veiculo_único_dono').to_frame().T
)
Número de nulos da variável `veiculo_único_dono`: 19161
| veiculo_único_dono | Único dono |
|---|---|
| 0 | 10423 |
# Trocando a varíavel para booleana
df['veiculo_único_dono'] = df.veiculo_único_dono.notnull()
df.groupby('veiculo_único_dono') \
.agg({'preco': ['count', 'mean', 'median', 'std']}) \
.preco.style.apply(highlight_max)
| count | mean | median | std | |
|---|---|---|---|---|
| veiculo_único_dono | ||||
| False | 19161 | 128559.986683 | 106966.355424 | 84655.561853 |
| True | 10423 | 141230.025669 | 125767.859016 | 75169.334800 |
plt.figure(figsize=(5, 5))
ax = sns.countplot(df, x='veiculo_único_dono', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.xlabel('Variável `veiculo_único_dono`')
plt.ylabel('Contagem')
plt.title('Contagem de veículos por variável `veiculo_único_dono`')
plt.show()
plt.figure(figsize=(5, 5))
ax = sns.histplot(df, x='preco', hue='veiculo_único_dono')
plt.xlabel('Preço')
plt.ylabel('Contagem')
plt.title('Histograma de preço dos veículos por variável `veiculo_único_dono`')
plt.show()
plt.figure(figsize=(5, 5))
ax = sns.boxplot(df, y='preco', x='veiculo_único_dono')
plt.xlabel('Variável `veiculo_único_dono`')
plt.ylabel('Preço')
plt.title('Boxplot de preço dos veículos por variável `veiculo_único_dono`')
plt.show()
# Variável `revisoes_concessionaria`
# Nulos
print(f'Número de nulos da variável `revisoes_concessionaria`: {df.revisoes_concessionaria.isna().sum()}')
# Contagem
display(
df.value_counts('revisoes_concessionaria').to_frame().T
)
Número de nulos da variável `revisoes_concessionaria`: 20412
| revisoes_concessionaria | Todas as revisões feitas pela concessionária |
|---|---|
| 0 | 9172 |
# Trocando a varíavel para booleana
df['revisoes_concessionaria'] = df.revisoes_concessionaria.notnull()
df.groupby('revisoes_concessionaria') \
.agg({'preco': ['count', 'mean', 'median', 'std']}) \
.preco.style.apply(highlight_max)
| count | mean | median | std | |
|---|---|---|---|---|
| revisoes_concessionaria | ||||
| False | 20412 | 123207.729899 | 105427.457768 | 76450.153810 |
| True | 9172 | 154869.415578 | 136218.519048 | 88386.359654 |
plt.figure(figsize=(5, 5))
ax = sns.countplot(df, x='revisoes_concessionaria', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.xlabel('Variável `revisoes_concessionaria`')
plt.ylabel('Contagem')
plt.title('Contagem de veículos por variável `revisoes_concessionaria`')
plt.show()
plt.figure(figsize=(5, 5))
ax = sns.histplot(df, x='preco', hue='revisoes_concessionaria')
plt.xlabel('Preço')
plt.ylabel('Contagem')
plt.title('Histograma de preço dos veículos por variável `revisoes_concessionaria`')
plt.show()
plt.figure(figsize=(5, 5))
ax = sns.boxplot(df, y='preco', x='revisoes_concessionaria')
plt.xlabel('Variável `revisoes_concessionaria`')
plt.ylabel('Preço')
plt.title('Boxplot de preço dos veículos por variável `revisoes_concessionaria`')
plt.show()
# Variável `ipva_pago`
# Nulos
print(f'Número de nulos da variável `ipva_pago`: {df.ipva_pago.isna().sum()}')
# Contagem
display(
df.value_counts('ipva_pago').to_frame().T
)
Número de nulos da variável `ipva_pago`: 9925
| ipva_pago | IPVA pago |
|---|---|
| 0 | 19659 |
# Trocando a varíavel para booleana
df['ipva_pago'] = df.ipva_pago.notnull()
df.groupby('ipva_pago') \
.agg({'preco': ['count', 'mean', 'median', 'std']}) \
.preco.style.apply(highlight_max)
| count | mean | median | std | |
|---|---|---|---|---|
| ipva_pago | ||||
| False | 9925 | 134180.535465 | 110141.626520 | 89237.267030 |
| True | 19659 | 132439.933257 | 116127.098683 | 77554.234135 |
plt.figure(figsize=(5, 5))
ax = sns.countplot(df, x='ipva_pago', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.xlabel('Variável `ipva_pago`')
plt.ylabel('Contagem')
plt.title('Contagem de veículos por variável `ipva_pago`')
plt.show()
plt.figure(figsize=(5, 5))
ax = sns.histplot(df, x='preco', hue='ipva_pago')
plt.xlabel('Preço')
plt.ylabel('Contagem')
plt.title('Histograma de preço dos veículos por variável `ipva_pago`')
plt.show()
plt.figure(figsize=(5, 5))
ax = sns.boxplot(df, y='preco', x='ipva_pago')
plt.xlabel('Variável `ipva_pago`')
plt.ylabel('Preço')
plt.title('Boxplot de preço dos veículos por variável `ipva_pago`')
plt.show()
# Variável `veiculo_licenciado`
# Nulos
print(f'Número de nulos da variável `veiculo_licenciado`: {df.veiculo_licenciado.isna().sum()}')
# Contagem
display(
df.value_counts('veiculo_licenciado').to_frame().T
)
Número de nulos da variável `veiculo_licenciado`: 13678
| veiculo_licenciado | Licenciado |
|---|---|
| 0 | 15906 |
# Trocando a varíavel para booleana
df['veiculo_licenciado'] = df.veiculo_licenciado.notnull()
df.groupby('veiculo_licenciado') \
.agg({'preco': ['count', 'mean', 'median', 'std']}) \
.preco.style.apply(highlight_max)
| count | mean | median | std | |
|---|---|---|---|---|
| veiculo_licenciado | ||||
| False | 13678 | 134422.188420 | 111318.815836 | 87877.582345 |
| True | 15906 | 131821.436513 | 116353.816979 | 75895.112850 |
plt.figure(figsize=(5, 5))
ax = sns.countplot(df, x='veiculo_licenciado', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.xlabel('Variável `veiculo_licenciado`')
plt.ylabel('Contagem')
plt.title('Contagem de veículos por variável `veiculo_licenciado`')
plt.show()
plt.figure(figsize=(5, 5))
ax = sns.histplot(df, x='preco', hue='veiculo_licenciado')
plt.xlabel('Preço')
plt.ylabel('Contagem')
plt.title('Histograma de preço dos veículos por variável `veiculo_licenciado`')
plt.show()
plt.figure(figsize=(5, 5))
ax = sns.boxplot(df, y='preco', x='veiculo_licenciado')
plt.xlabel('Variável `veiculo_licenciado`')
plt.ylabel('Preço')
plt.title('Boxplot de preço dos veículos por variável `veiculo_licenciado`')
plt.show()
# Variável `garantia_de_fábrica`
# Nulos
print(f'Número de nulos da variável `garantia_de_fábrica`: {df.garantia_de_fábrica.isna().sum()}')
# Contagem
display(
df.value_counts('garantia_de_fábrica').to_frame().T
)
Número de nulos da variável `garantia_de_fábrica`: 25219
| garantia_de_fábrica | Garantia de fábrica |
|---|---|
| 0 | 4365 |
# Trocando a varíavel para booleana
df['garantia_de_fábrica'] = df.garantia_de_fábrica.notnull()
df.groupby('garantia_de_fábrica') \
.agg({'preco': ['count', 'mean', 'median', 'std']}) \
.preco.style.apply(highlight_max)
| count | mean | median | std | |
|---|---|---|---|---|
| garantia_de_fábrica | ||||
| False | 25219 | 126798.184924 | 108545.015442 | 79534.901258 |
| True | 4365 | 168993.135573 | 148528.910604 | 84465.960948 |
plt.figure(figsize=(5, 5))
ax = sns.countplot(df, x='garantia_de_fábrica', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.xlabel('Variável `garantia_de_fábrica`')
plt.ylabel('Contagem')
plt.title('Contagem de veículos por variável `garantia_de_fábrica`')
plt.show()
plt.figure(figsize=(5, 5))
ax = sns.histplot(df, x='preco', hue='garantia_de_fábrica')
plt.xlabel('Preço')
plt.ylabel('Contagem')
plt.title('Histograma de preço dos veículos por variável `garantia_de_fábrica`')
plt.show()
plt.figure(figsize=(5, 5))
ax = sns.boxplot(df, y='preco', x='garantia_de_fábrica')
plt.xlabel('Variável `garantia_de_fábrica`')
plt.ylabel('Preço')
plt.title('Boxplot de preço dos veículos por variável `garantia_de_fábrica`')
plt.show()
# Variável `revisoes_dentro_agenda`
# Nulos
print(f'Número de nulos da variável `revisoes_dentro_agenda`: {df.revisoes_dentro_agenda.isna().sum()}')
# Contagem
display(
df.value_counts('revisoes_dentro_agenda').to_frame().T
)
Número de nulos da variável `revisoes_dentro_agenda`: 23674
| revisoes_dentro_agenda | Todas as revisões feitas pela agenda do carro |
|---|---|
| 0 | 5910 |
# Trocando a varíavel para booleana
df['revisoes_dentro_agenda'] = df.revisoes_dentro_agenda.notnull()
df.groupby('revisoes_dentro_agenda') \
.agg({'preco': ['count', 'mean', 'median', 'std']}) \
.preco.style.apply(highlight_max)
| count | mean | median | std | |
|---|---|---|---|---|
| revisoes_dentro_agenda | ||||
| False | 23674 | 128264.417179 | 109732.828873 | 79557.260682 |
| True | 5910 | 152089.111689 | 134597.274873 | 87038.190591 |
plt.figure(figsize=(5, 5))
ax = sns.countplot(df, x='revisoes_dentro_agenda', color='lightcoral')
ax.bar_label(ax.containers[0])
plt.xlabel('Variável `revisoes_dentro_agenda`')
plt.ylabel('Contagem')
plt.title('Contagem de veículos por variável `revisoes_dentro_agenda`')
plt.show()
plt.figure(figsize=(5, 5))
ax = sns.histplot(df, x='preco', hue='revisoes_dentro_agenda')
plt.xlabel('Preço')
plt.ylabel('Contagem')
plt.title('Histograma de preço dos veículos por variável `revisoes_dentro_agenda`')
plt.show()
plt.figure(figsize=(5, 5))
ax = sns.boxplot(df, y='preco', x='revisoes_dentro_agenda')
plt.xlabel('Variável `revisoes_dentro_agenda`')
plt.ylabel('Preço')
plt.title('Boxplot de preço dos veículos por variável `revisoes_dentro_agenda`')
plt.show()
# Variável `veiculo_alienado`
# Nulos
print(f'Número de nulos da variável `veiculo_alienado`: {df.veiculo_alienado.isna().sum()}')
# Contagem
display(
df.value_counts('veiculo_alienado').to_frame().T
)
Número de nulos da variável `veiculo_alienado`: 29584
| veiculo_alienado |
|---|
| 0 |
Não há nenhum veículo alienado.
# Variável `preco`
# Nulos
print(f'Número de nulos da variável `preco`: {df.preco.isna().sum()}')
plt.figure(figsize=(12, 5))
ax = sns.histplot(df, x='preco')
plt.xlabel('Preço')
plt.ylabel('Contagem')
plt.title('Histograma dos preços dos veículos')
plt.show()
Número de nulos da variável `preco`: 0
display(df.sort_values('preco').head())
| id | num_fotos | marca | modelo | versao | ano_de_fabricacao | ano_modelo | hodometro | cambio | num_portas | tipo | blindado | cor | vendedor_PJ | cidade_vendedor | estado_vendedor | anunciante | entrega_delivery | troca | elegivel_revisao | dono_aceita_troca | veiculo_único_dono | revisoes_concessionaria | ipva_pago | veiculo_licenciado | garantia_de_fábrica | revisoes_dentro_agenda | veiculo_alienado | preco | diferenca_ano | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 3930 | 301661037804328286615953008015027061532 | 8 | VOLKSWAGEN | FUSCA | 1.6 8V GASOLINA 2P MANUAL | 1992 | 2012 | 222321.0 | Manual | 4 | Sedã | False | Prata | False | Jaguaruna | Santa Catarina (SC) | Pessoa Física | False | False | False | True | False | False | True | False | False | False | NaN | 9869.950645 | 20 |
| 26359 | 226619116291182635743624724700616484456 | 8 | PEUGEOT | 307 | 1.6 PRESENCE SEDAN 16V FLEX 4P MANUAL | 1998 | 2012 | 119731.0 | Manual | 4 | Sedã | False | Preto | False | Osasco | São Paulo (SP) | Pessoa Física | False | False | False | False | False | False | True | True | False | False | NaN | 11606.398045 | 14 |
| 5497 | 301737368863860882436657500276489502131 | 8 | PEUGEOT | 207 | 1.4 XR SPORT 8V FLEX 4P MANUAL | 1999 | 2013 | 128769.0 | Manual | 4 | Hatchback | False | Preto | False | Brotas | São Paulo (SP) | Pessoa Física | False | False | False | False | False | True | True | False | False | True | NaN | 13576.401422 | 14 |
| 18200 | 279125074222685494207525095206614870117 | 15 | FIAT | PALIO | 1.0 MPI FIRE ECONOMY 8V FLEX 2P MANUAL | 2008 | 2012 | 138482.0 | Manual | 4 | Picape | False | Prata | True | Rio de Janeiro | São Paulo (SP) | Loja | True | True | False | True | False | False | False | False | False | False | NaN | 13642.891063 | 4 |
| 16180 | 72843072145688843461062591189140131966 | 14 | FIAT | STRADA | 1.4 MPI WORKING CS 8V FLEX 2P MANUAL | 2015 | 2015 | 86105.0 | Manual | 4 | Picape | False | Branco | False | Osasco | São Paulo (SP) | Pessoa Física | False | False | False | True | False | False | False | False | False | False | NaN | 14011.654277 | 0 |
display(df.sort_values('preco', ascending=False).head())
| id | num_fotos | marca | modelo | versao | ano_de_fabricacao | ano_modelo | hodometro | cambio | num_portas | tipo | blindado | cor | vendedor_PJ | cidade_vendedor | estado_vendedor | anunciante | entrega_delivery | troca | elegivel_revisao | dono_aceita_troca | veiculo_único_dono | revisoes_concessionaria | ipva_pago | veiculo_licenciado | garantia_de_fábrica | revisoes_dentro_agenda | veiculo_alienado | preco | diferenca_ano | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 9175 | 308503071796180546584015995459795952963 | 13 | PORSCHE | 911 | 3.0 24V H6 GASOLINA TARGA 4S PDK | 2014 | 2017 | 10249.0 | Automática | 2 | Picape | False | Branco | True | Cocalzinho de Goiás | Santa Catarina (SC) | Loja | True | True | False | True | False | False | False | False | False | False | NaN | 1.359813e+06 | 3 |
| 15111 | 43158431735708352041169148103055117190 | 17 | LAND ROVER | RANGE ROVER VELAR | 3.0 V6 P380 GASOLINA R-DYNAMIC HSE AUTOMÁTICO | 2018 | 2019 | 6199.0 | Automática | 4 | Utilitário esportivo | False | Branco | True | Goiânia | Goiás (GO) | Loja | False | False | False | True | False | False | False | False | False | False | NaN | 1.349748e+06 | 1 |
| 2271 | 80859761199167937486296054000762167416 | 8 | RAM | 2500 | 6.7 I6 TURBO DIESEL LARAMIE CD 4X4 AUTOMÁTICO | 2019 | 2020 | 10993.0 | Automática | 4 | Picape | False | Preto | False | São Paulo | São Paulo (SP) | Pessoa Física | False | False | False | True | False | False | False | False | False | False | NaN | 1.154360e+06 | 1 |
| 4844 | 128068977712443763554635933612117555753 | 15 | PORSCHE | 911 | 3.0 24V H6 GASOLINA TARGA 4 GTS PDK | 2019 | 2019 | 10058.0 | Manual | 2 | Picape | False | Branco | True | São Paulo | São Paulo (SP) | Loja | True | True | False | True | False | True | False | False | False | False | NaN | 1.140113e+06 | 0 |
| 21827 | 155547567848928485806288559744566635721 | 17 | PORSCHE | 718 | 2.0 16V H4 GASOLINA CAYMAN PDK | 2015 | 2015 | 12667.0 | Automática | 4 | Picape | False | Branco | False | Sorocaba | São Paulo (SP) | Pessoa Física | False | False | False | True | False | False | False | False | False | False | NaN | 1.028431e+06 | 0 |
Vamos visualizar também como se comporta a variável preço aplicando log10.
plt.figure(figsize=(12, 5))
ax = sns.histplot(x=df['preco'].apply(np.log10))
plt.xlabel('Preço')
plt.ylabel('Contagem')
plt.title('Histograma dos preços dos veículos')
plt.show()
Primeiramente, precisamos estabelecer alguns critérios para definir as marcas de carro popular. Podemos estabelecer, por exemplo, que seriam as 10 marcas com maior número de veículos vendidos:
top10_marcas_populares = df.marca.value_counts().head(10).reset_index()
display(top10_marcas_populares)
top10_marcas_populares = top10_marcas_populares['index'].to_list()
| index | marca | |
|---|---|---|
| 0 | VOLKSWAGEN | 4594 |
| 1 | CHEVROLET | 3020 |
| 2 | TOYOTA | 2180 |
| 3 | HYUNDAI | 2043 |
| 4 | JEEP | 2000 |
| 5 | FIAT | 1918 |
| 6 | BMW | 1784 |
| 7 | AUDI | 1698 |
| 8 | PEUGEOT | 1675 |
| 9 | HONDA | 1586 |
O melhor estado para se vender seria o que apresenta os maiores valores para essas marcas, conforme tabela a seguir:
df[df.marca.isin(top10_marcas_populares)] \
.groupby('estado_vendedor') \
.agg({'preco':['count','mean', 'median', 'std', 'min', 'max']}) \
.preco.sort_values('median', ascending=False).head(10) \
.style.apply(highlight_max)
| count | mean | median | std | min | max | |
|---|---|---|---|---|---|---|
| estado_vendedor | ||||||
| Sergipe (SE) | 21 | 213336.639963 | 206061.458453 | 117484.905670 | 44862.086264 | 464786.417184 |
| Piauí (PI) | 5 | 166998.772866 | 147846.624243 | 58577.668348 | 108140.818284 | 240243.176208 |
| Mato Grosso (MT) | 30 | 133451.917692 | 141345.646921 | 46933.274919 | 59040.523844 | 269004.832557 |
| Goiás (GO) | 642 | 143927.033950 | 132883.629793 | 69083.760178 | 30259.720035 | 563706.675284 |
| Pará (PA) | 71 | 121081.184877 | 131128.530217 | 43168.318853 | 40905.991953 | 205115.738807 |
| Rondônia (RO) | 4 | 118363.820745 | 124570.628021 | 15956.859480 | 94700.110904 | 129613.916033 |
| Maranhão (MA) | 7 | 121041.689127 | 124370.609094 | 15134.135692 | 92743.077566 | 137709.162135 |
| Paraná (PR) | 1882 | 138899.873208 | 123716.539246 | 75827.544808 | 18525.084443 | 643743.124813 |
| Rio Grande do Sul (RS) | 1237 | 132800.364221 | 120269.015633 | 70442.222411 | 18394.092756 | 589418.739087 |
| Minas Gerais (MG) | 1345 | 126774.791558 | 114472.528084 | 67693.304313 | 14464.694571 | 558800.215763 |
Sergipe seria o melhor estado, porém há relativamente pouco volume para essas marcas. Podemos optar também por Goiás, caso seja de interesse um estado com maior demanda.
Sobre a definição de marca popular, podemos também optar pelas marcas com preços mais baixos e que tenham uma boa quantidade de veículos vendidos.
Vamos agrupar os veículos por marcas e agregar os valores por preço, apresentando a mediana (uma vez que é uma medida que sofre menos influência de outliers) e a contagem de veículos vendidos.
marcas_populares = df.groupby('marca').agg({'preco': ['count', 'median']}).preco.sort_values('median').reset_index()
marcas_populares.head(10)
| marca | count | median | |
|---|---|---|---|
| 0 | EFFA | 1 | 40163.175829 |
| 1 | BRM | 1 | 47762.671073 |
| 2 | CHRYSLER | 30 | 57530.513198 |
| 3 | CITROËN | 194 | 61708.494392 |
| 4 | SMART | 12 | 66929.542662 |
| 5 | ALFA ROMEO | 9 | 69926.750037 |
| 6 | SSANGYONG | 14 | 73173.086612 |
| 7 | RENAULT | 538 | 75871.664317 |
| 8 | DODGE | 37 | 76463.935136 |
| 9 | HYUNDAI | 2043 | 77118.762163 |
Como critério para "popularidade" vamos arbitrariamente tomar apenas as marcas com mais de 200 vendas, e selecionar apenas os 10 menores preços:
display(marcas_populares[marcas_populares['count'] > 200].head(10))
top10_marcas_populares = marcas_populares[marcas_populares['count'] > 200].head(10).marca
| marca | count | median | |
|---|---|---|---|
| 7 | RENAULT | 538 | 75871.664317 |
| 9 | HYUNDAI | 2043 | 77118.762163 |
| 10 | CHEVROLET | 3020 | 79934.798236 |
| 14 | HONDA | 1586 | 91506.027179 |
| 15 | NISSAN | 438 | 91691.281136 |
| 16 | FIAT | 1918 | 93202.070187 |
| 17 | VOLKSWAGEN | 4594 | 103350.092101 |
| 18 | FORD | 1060 | 103619.715970 |
| 22 | MITSUBISHI | 862 | 117222.069832 |
| 23 | KIA | 408 | 118306.655455 |
Agora vamos selecionar apenas essas marcas e comparar os preços praticados em cada estado.
df[df.marca.isin(top10_marcas_populares)] \
.groupby('estado_vendedor') \
.agg({'preco':['count','mean', 'median', 'std', 'min', 'max']}) \
.preco.sort_values('median', ascending=False).head(10) \
.style.apply(highlight_max)
| count | mean | median | std | min | max | |
|---|---|---|---|---|---|---|
| estado_vendedor | ||||||
| Piauí (PI) | 5 | 190915.177367 | 216911.669785 | 52651.102796 | 121851.575810 | 240243.176208 |
| Mato Grosso (MT) | 13 | 157018.833917 | 151668.104816 | 73833.372366 | 59040.523844 | 276335.895881 |
| Maranhão (MA) | 3 | 131409.088091 | 132147.493043 | 6699.864231 | 124370.609094 | 137709.162135 |
| Rondônia (RO) | 3 | 126251.724025 | 124944.374446 | 2935.632422 | 124196.881596 | 129613.916033 |
| Alagoas (AL) | 91 | 116743.592287 | 111000.653518 | 52892.433617 | 39477.019067 | 261985.267235 |
| Goiás (GO) | 397 | 123433.359126 | 108714.487224 | 59931.908449 | 30259.720035 | 586482.460906 |
| Sergipe (SE) | 7 | 138379.742270 | 107977.590744 | 119572.701842 | 44862.086264 | 362349.952794 |
| Tocantins (TO) | 12 | 112045.099468 | 105092.431438 | 60474.289648 | 43722.062552 | 243002.217032 |
| Paraná (PR) | 1261 | 115438.626341 | 101659.181500 | 61899.916245 | 18525.084443 | 429236.244325 |
| Rio Grande do Sul (RS) | 823 | 112920.089775 | 100793.737925 | 61550.573135 | 18394.092756 | 540419.510242 |
Podemos utilizar os boxplots abaixo para avaliar os estados. Basta verificar quão à direita a linha central do boxplot (que representa a mediana) está localizada no eixo x.
plt.figure(figsize=(7, 7))
sns.boxplot(df[df.marca.isin(top10_marcas_populares)], y='estado_vendedor', x='preco')
plt.show()
O estado com a maior média de preço para as marcas populares foi o Piauí. Contudo, devemos nos atentar ao fato de que o mesmo possui apenas 5 vendas, o que é representativamente pouco.
Podemos optar então por vender em Alagoas (91 vendas realizadas das marcas populares) ou em Goiás (397 vendas).
Vamos filtrar apenas as picapes com transmissão automática.
picapes_automaticas = df[(df.tipo == 'Picape') & (df.cambio == 'Automática')]
picapes_automaticas.head()
| id | num_fotos | marca | modelo | versao | ano_de_fabricacao | ano_modelo | hodometro | cambio | num_portas | tipo | blindado | cor | vendedor_PJ | cidade_vendedor | estado_vendedor | anunciante | entrega_delivery | troca | elegivel_revisao | dono_aceita_troca | veiculo_único_dono | revisoes_concessionaria | ipva_pago | veiculo_licenciado | garantia_de_fábrica | revisoes_dentro_agenda | veiculo_alienado | preco | diferenca_ano | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 3 | 56862509826849933428086372390159405545 | 14 | VOLKSWAGEN | AMAROK | 2.0 HIGHLINE 4X4 CD 16V TURBO INTERCOOLER DIES... | 2013 | 2015 | 85357.0 | Automática | 4 | Picape | False | Branco | True | Sorocaba | São Paulo (SP) | Loja | True | True | False | True | False | False | True | True | False | False | NaN | 123681.358857 | 2 |
| 48 | 288950486904285252834098132344068709579 | 8 | VOLKSWAGEN | GOLF | 1.4 TSI HIGHLINE 16V GASOLINA 4P AUTOMÁTICO | 2013 | 2015 | 61472.0 | Automática | 4 | Picape | False | Branco | False | Sorocaba | São Paulo (SP) | Pessoa Física | False | False | False | False | False | True | True | True | False | True | NaN | 86304.702755 | 2 |
| 61 | 35429253802991633165448719135914498665 | 8 | FIAT | TORO | 1.8 16V EVO FLEX FREEDOM AT6 | 2017 | 2017 | 101623.0 | Automática | 4 | Picape | False | Branco | False | São Paulo | São Paulo (SP) | Pessoa Física | False | False | False | True | False | False | False | False | False | False | NaN | 89522.637708 | 0 |
| 65 | 328880961834833259252462744533448193192 | 16 | MINI | COOPER | 1.6 S CABRIO 16V TURBO GASOLINA 2P AUTOMÁTICO | 2013 | 2014 | 1336.0 | Automática | 2 | Picape | False | Branco | False | Santos | São Paulo (SP) | Pessoa Física | False | False | False | True | False | False | False | False | False | False | NaN | 217524.354433 | 1 |
| 79 | 46988346268821185308430847707885811630 | 8 | MERCEDES-BENZ | CLS 350 | 3.5 CGI V6 GASOLINA 4P AUTOMÁTICO | 2013 | 2014 | 93979.0 | Automática | 4 | Picape | False | Branco | False | Rio de Janeiro | Rio de Janeiro (RJ) | Pessoa Física | False | False | False | False | False | True | True | True | False | True | NaN | 364010.202406 | 1 |
Agora vamos agrupar por estado e verificar qual estado possui os menores preços.
picapes_automaticas.groupby('estado_vendedor') \
.agg({'preco': ['count', 'mean', 'median', 'std', 'min', 'max']}) \
.preco.sort_values('median').style\
.apply(highlight_min)
| count | mean | median | std | min | max | |
|---|---|---|---|---|---|---|
| estado_vendedor | ||||||
| Paraíba (PB) | 4 | 93157.035264 | 94749.617465 | 15280.821664 | 73223.791078 | 109905.115048 |
| Acre (AC) | 6 | 145256.693656 | 140874.296899 | 67928.510680 | 56452.605869 | 228022.077115 |
| Mato Grosso do Sul (MS) | 5 | 144700.247621 | 140939.840926 | 60465.160895 | 51084.109261 | 201950.263985 |
| Rio de Janeiro (RJ) | 318 | 181660.344685 | 158427.721631 | 84677.479836 | 26729.716235 | 486869.600468 |
| São Paulo (SP) | 1712 | 188427.484638 | 163250.712832 | 105203.461173 | 15953.204811 | 1154360.165470 |
| Santa Catarina (SC) | 283 | 185848.618546 | 164922.902158 | 114099.879173 | 41524.669174 | 1359812.892309 |
| Rio Grande do Norte (RN) | 1 | 179961.694768 | 179961.694768 | nan | 179961.694768 | 179961.694768 |
| Rio Grande do Sul (RS) | 198 | 195251.763134 | 182066.354685 | 91456.494604 | 40222.467536 | 540419.510242 |
| Minas Gerais (MG) | 211 | 195702.914796 | 183793.340535 | 92135.235476 | 58014.160096 | 653173.284756 |
| Goiás (GO) | 102 | 208153.658437 | 190140.227824 | 100476.424902 | 72266.197406 | 586482.460906 |
| Paraná (PR) | 348 | 198384.949644 | 190552.679135 | 90510.890600 | 33474.730405 | 550147.008331 |
| Tocantins (TO) | 3 | 187717.127524 | 198376.246681 | 61313.524607 | 121772.918859 | 243002.217032 |
| Bahia (BA) | 68 | 206364.799217 | 199106.366953 | 84220.375390 | 61529.782003 | 439684.821162 |
| Mato Grosso (MT) | 6 | 214102.315642 | 214604.896356 | 39038.162893 | 167591.880160 | 276335.895881 |
| Pernambuco (PE) | 14 | 192566.764505 | 216824.428287 | 89384.835314 | 75521.478610 | 323895.123501 |
| Piauí (PI) | 4 | 208181.077756 | 222317.255287 | 41337.344607 | 147846.624243 | 240243.176208 |
| Alagoas (AL) | 12 | 218671.542780 | 230393.237674 | 85424.677647 | 52207.250003 | 345006.894744 |
| Sergipe (SE) | 5 | 298195.309673 | 292493.757273 | 69625.523392 | 233540.340367 | 400378.477403 |
Paraíba é o estado com as picapes automáticas mais baratas, contudo foram vendidas apenas 4. Caso necessite-se de um estado com maior número de veículos vendidos poderia se optar pelo Rio de Janeiro, com 318 vendas.
sns.boxplot(picapes_automaticas, y='estado_vendedor', x='preco')
<Axes: xlabel='preco', ylabel='estado_vendedor'>
Vamos selecionar apenas os veículos com garantia de fábrica, agrupar por estados e agregar os valores por preço:
df[df.garantia_de_fábrica == True]\
.groupby('estado_vendedor') \
.agg({'preco': ['count', 'mean', 'median', 'std', 'min', 'max']}) \
.preco.sort_values('median').style.apply(highlight_min)
| count | mean | median | std | min | max | |
|---|---|---|---|---|---|---|
| estado_vendedor | ||||||
| Pará (PA) | 17 | 98156.615283 | 87914.540316 | 40697.738199 | 43906.629995 | 169004.077906 |
| Paraíba (PB) | 1 | 95762.746630 | 95762.746630 | nan | 95762.746630 | 95762.746630 |
| Amazonas (AM) | 9 | 99617.303347 | 101150.518799 | 28311.343848 | 54908.191330 | 140166.897144 |
| Espírito Santo (ES) | 9 | 104030.208116 | 105139.248966 | 33632.761297 | 49919.575982 | 147312.316884 |
| Mato Grosso do Sul (MS) | 13 | 121709.589845 | 112242.882310 | 37918.919435 | 85730.862915 | 223508.570609 |
| Ceará (CE) | 1 | 123939.878795 | 123939.878795 | nan | 123939.878795 | 123939.878795 |
| Rio Grande do Norte (RN) | 9 | 133120.393894 | 132364.271297 | 77498.786709 | 54848.887128 | 302058.400392 |
| Alagoas (AL) | 58 | 154268.676544 | 134200.249180 | 76038.793890 | 55178.097786 | 353250.074635 |
| Minas Gerais (MG) | 264 | 161206.273890 | 142744.989022 | 76856.771415 | 29906.894268 | 426790.142244 |
| Rio Grande do Sul (RS) | 281 | 176442.236455 | 147604.803119 | 89532.093833 | 54742.833352 | 589418.739087 |
| São Paulo (SP) | 2307 | 166751.081004 | 147730.532941 | 83009.688864 | 31763.159542 | 677129.123324 |
| Goiás (GO) | 186 | 174521.413156 | 148835.418103 | 90809.754431 | 45812.306967 | 486648.154645 |
| Santa Catarina (SC) | 330 | 173798.439853 | 149273.680372 | 93082.399439 | 44004.769748 | 672933.092917 |
| Bahia (BA) | 51 | 165221.236199 | 149887.959028 | 86728.918503 | 33100.914663 | 351109.005575 |
| Acre (AC) | 2 | 150416.911346 | 150416.911346 | 109750.277941 | 72811.745577 | 228022.077115 |
| Pernambuco (PE) | 20 | 149898.416932 | 151139.460006 | 65277.391553 | 55243.838003 | 282732.009352 |
| Paraná (PR) | 389 | 175578.245503 | 156357.553200 | 82210.721670 | 29328.116594 | 429236.244325 |
| Rio de Janeiro (RJ) | 412 | 179109.858403 | 162092.343056 | 86161.814458 | 39556.398656 | 486869.600468 |
| Mato Grosso (MT) | 2 | 197657.066561 | 197657.066561 | 26478.404920 | 178934.006888 | 216380.126235 |
| Tocantins (TO) | 1 | 243002.217032 | 243002.217032 | nan | 243002.217032 | 243002.217032 |
| Sergipe (SE) | 3 | 367138.430255 | 328272.278075 | 85149.900860 | 308356.595507 | 464786.417184 |
Pará é o estado com menores preços (mediana) dos carros dentro da garantia. Caso opte-se para um estado com mais veículos vendidos, poderia ser escolhido Minas Gerais.
Antes de formularmos hipóteses sobre os dados apresentados, vamos analisar as correlações entre as variáveis:
df = df[['id', 'num_fotos', 'marca', 'modelo', 'versao', 'ano_de_fabricacao',
'ano_modelo', 'hodometro', 'cambio', 'num_portas', 'tipo', 'blindado',
'cor', 'vendedor_PJ', 'cidade_vendedor', 'estado_vendedor',
'anunciante', 'entrega_delivery', 'troca', 'elegivel_revisao',
'dono_aceita_troca', 'veiculo_único_dono', 'revisoes_concessionaria',
'ipva_pago', 'veiculo_licenciado', 'garantia_de_fábrica',
'revisoes_dentro_agenda', 'veiculo_alienado', 'diferenca_ano', 'preco']]
plt.figure(figsize=(15, 10))
sns.heatmap(df.corr(numeric_only=True), annot=True, cmap=sns.diverging_palette(20, 220, n=200),)
plt.show()
As features, em geral, não apresentam fortes correlações com a variável preço. As que mais apresentaram algum tipo de correlação foram hodômetro (negativa) e ano de fabricação/modelo (positiva).
Algumas hipóteses de negócio:
ipva_pago está relacionada com os estados, uma vez que o IPVA é um imposto com alíquotas diferentes por estado;Um comportamento que me chamou atenção foi com relação a variável vendedor_PJ. A seguir o mapa de calor das correlações da variável:
plt.figure(figsize=(5, 6))
sns.heatmap(df.corr(numeric_only=True).vendedor_PJ.to_frame(), annot=True, cmap=sns.diverging_palette(20, 220, n=200),)
plt.ylabel('Features')
plt.title('Heatmap das correlações da variável `vendedor_PJ`')
plt.show()
print(f'Número de vendedores PF: {df.vendedor_PJ.value_counts()[False]} ({df.vendedor_PJ.value_counts()[False]/df.shape[0] * 100:.2f}%)')
print(f'Número de vendedores PJ: {df.vendedor_PJ.value_counts()[True]} ({df.vendedor_PJ.value_counts()[True]/df.shape[0] * 100:.2f}%)')
Número de vendedores PF: 17926 (60.59%) Número de vendedores PJ: 11658 (39.41%)
df.groupby('vendedor_PJ').entrega_delivery.value_counts(normalize=True)
vendedor_PJ entrega_delivery
False False 1.00000
True True 0.51321
False 0.48679
Name: entrega_delivery, dtype: float64
df.groupby('vendedor_PJ').troca.value_counts(normalize=True)
vendedor_PJ troca
False False 1.000000
True False 0.565878
True 0.434122
Name: troca, dtype: float64
df.groupby('vendedor_PJ').dono_aceita_troca.value_counts(normalize=True)
vendedor_PJ dono_aceita_troca
False True 0.572576
False 0.427424
True True 1.000000
Name: dono_aceita_troca, dtype: float64
Apenas vendedores PJ fazem delivery e tem veículos trocados anteriormente. Além disso, todos os vendedores PJ aceitam trocas.
df.groupby('vendedor_PJ').num_fotos.value_counts()
vendedor_PJ num_fotos
False 8 17672
16 65
15 57
0 38
14 31
17 19
9 12
20 12
13 9
18 7
11 2
12 1
19 1
True 15 2707
16 2162
14 1780
8 1748
17 966
9 716
13 708
20 274
18 241
12 146
0 139
19 44
11 19
21 5
10 3
Name: num_fotos, dtype: int64
print(f"Total de fotos quando o vendedor é PF: {df.groupby('vendedor_PJ').num_fotos.sum()[False]}")
print(f"Total de fotos quando o vendedor é PJ: {df.groupby('vendedor_PJ').num_fotos.sum()[True]}")
Total de fotos quando o vendedor é PF: 144672 Total de fotos quando o vendedor é PJ: 158921
Em geral vendedores PF anunciam com apenas 8 fotos, enquanto que vendedores PJ tendem a anunciar com mais fotos.
df.groupby('vendedor_PJ').ipva_pago.value_counts(normalize=True)
vendedor_PJ ipva_pago
False True 0.768493
False 0.231507
True True 0.504632
False 0.495368
Name: ipva_pago, dtype: float64
Vendedores PF tendem a pagar o IPVA com mais frequência.
df.groupby('vendedor_PJ').revisoes_concessionaria.value_counts(normalize=True)
vendedor_PJ revisoes_concessionaria
False False 0.541671
True 0.458329
True False 0.917996
True 0.082004
Name: revisoes_concessionaria, dtype: float64
df.groupby('vendedor_PJ').revisoes_dentro_agenda.value_counts(normalize=True)
vendedor_PJ revisoes_dentro_agenda
False False 0.677675
True 0.322325
True False 0.988677
True 0.011323
Name: revisoes_dentro_agenda, dtype: float64
df.groupby('vendedor_PJ').garantia_de_fábrica.value_counts(normalize=True)
vendedor_PJ garantia_de_fábrica
False False 0.780989
True 0.219011
True False 0.962343
True 0.037657
Name: garantia_de_fábrica, dtype: float64
Vendedores PJ raramente fazem revisões na concessionária, estão com as revisões em dia e apresentam garantia de fábrica.
df.groupby(['vendedor_PJ', 'veiculo_único_dono']).dono_aceita_troca.value_counts(normalize=True)
vendedor_PJ veiculo_único_dono dono_aceita_troca
False False True 0.754610
False 0.245390
True False 0.736383
True 0.263617
True False True 1.000000
True True 1.000000
Name: dono_aceita_troca, dtype: float64
Quando o vendedor é PF e é o único dono do veículo, dificilmente aceita trocas. Em contrapartida, se o veículo teve mais de um dono, o dono geralmente aceita trocas.
ipva_pago é menos frequente em estados com alíquotas maiores¶Vamos carregar os valores das alíquotas do IPVA para cada estado. As informações foram obtidas deste artigo.
ipva_aliquotas = pd.read_excel('./dataset/aliquotas_ipva.xlsx', decimal=',')
ipva_aliquotas
| estado | aliquota | |
|---|---|---|
| 0 | Acre (AC) | 0.0200 |
| 1 | Alagoas (AL) | 0.0300 |
| 2 | Amazonas (AM) | 0.0300 |
| 3 | Bahia (BA) | 0.0250 |
| 4 | Ceará (CE) | 0.0250 |
| 5 | Espírito Santo (ES) | 0.0200 |
| 6 | Goiás (GO) | 0.0375 |
| 7 | Maranhão (MA) | 0.0250 |
| 8 | Minas Gerais (MG) | 0.0400 |
| 9 | Mato Grosso (MT) | 0.0300 |
| 10 | Mato Grosso do Sul (MS) | 0.0300 |
| 11 | Pará (PA) | 0.0250 |
| 12 | Paraíba (PB) | 0.0250 |
| 13 | Paraná (PR) | 0.0350 |
| 14 | Pernambuco (PE) | 0.0250 |
| 15 | Piauí (PI) | 0.0250 |
| 16 | Rio de Janeiro (RJ) | 0.0400 |
| 17 | Rio Grande do Norte (RN) | 0.0300 |
| 18 | Rio Grande do Sul (RS) | 0.0300 |
| 19 | Rondônia (RO) | 0.0300 |
| 20 | Roraima (RR) | 0.0300 |
| 21 | Santa Catarina (SC) | 0.0200 |
| 22 | São Paulo (SP) | 0.0300 |
| 23 | Sergipe (SE) | 0.0400 |
| 24 | Tocantins (TO) | 0.0200 |
Agora vamos comparar a contagem da variável ipva_pago com as respectivas alíquotas de cada estado.
ipva_pago_estado = df.groupby('estado_vendedor')\
.ipva_pago.value_counts(normalize=True)\
.to_frame().rename(columns={'ipva_pago': 'frequencia'})\
.reset_index()
ipva_pago_estado = ipva_pago_estado[ipva_pago_estado['ipva_pago'] == True].drop(columns=['ipva_pago'])
estado_ipva = ipva_pago_estado.merge(ipva_aliquotas, left_on='estado_vendedor', right_on='estado', how='left').drop(columns='estado')
estado_ipva
| estado_vendedor | frequencia | aliquota | |
|---|---|---|---|
| 0 | Acre (AC) | 0.310345 | 0.0200 |
| 1 | Alagoas (AL) | 1.000000 | 0.0300 |
| 2 | Amazonas (AM) | 0.490196 | 0.0300 |
| 3 | Bahia (BA) | 0.317881 | 0.0250 |
| 4 | Ceará (CE) | 0.826087 | 0.0250 |
| 5 | Espírito Santo (ES) | 0.714286 | 0.0200 |
| 6 | Goiás (GO) | 0.798479 | 0.0375 |
| 7 | Maranhão (MA) | 1.000000 | 0.0250 |
| 8 | Mato Grosso (MT) | 0.939394 | 0.0300 |
| 9 | Mato Grosso do Sul (MS) | 0.914286 | 0.0300 |
| 10 | Minas Gerais (MG) | 0.626479 | 0.0400 |
| 11 | Paraná (PR) | 0.570863 | 0.0350 |
| 12 | Paraíba (PB) | 0.537037 | 0.0250 |
| 13 | Pará (PA) | 1.000000 | 0.0250 |
| 14 | Pernambuco (PE) | 0.223270 | 0.0250 |
| 15 | Piauí (PI) | 1.000000 | 0.0250 |
| 16 | Rio Grande do Norte (RN) | 0.555556 | 0.0300 |
| 17 | Rio Grande do Sul (RS) | 0.743621 | 0.0300 |
| 18 | Rio de Janeiro (RJ) | 0.707614 | 0.0400 |
| 19 | Rondônia (RO) | 1.000000 | 0.0300 |
| 20 | Santa Catarina (SC) | 0.519548 | 0.0200 |
| 21 | Sergipe (SE) | 0.125000 | 0.0400 |
| 22 | São Paulo (SP) | 0.701123 | 0.0300 |
| 23 | Tocantins (TO) | 0.500000 | 0.0200 |
plt.figure(figsize=(5, 5))
sns.scatterplot(estado_ipva, x='aliquota', y='frequencia')
plt.xticks(np.arange(.02, .041, .01))
plt.xlabel('Alíquota')
plt.ylabel('Frequência de `ipva_pago`')
plt.title('Alíquota do IPVA x Frequência de `ipva_pago`')
plt.show()
estado_ipva.corr(numeric_only=True)
| frequencia | aliquota | |
|---|---|---|
| frequencia | 1.000000 | 0.007877 |
| aliquota | 0.007877 | 1.000000 |
Não há uma correlação entre a frequência de pagamento do IPVA com a alíquota de cada estado.
populacao_pib = pd.read_excel('./dataset/populacao_pib.xlsx')
populacao_pib
| estado | populacao | pib_per_capita | |
|---|---|---|---|
| 0 | Acre (AC) | 830026 | 18420.26 |
| 1 | Alagoas (AL) | 3127511 | 18857.69 |
| 2 | Amazonas (AM) | 3941175 | 27572.96 |
| 3 | Bahia (BA) | 14136417 | 20449.29 |
| 4 | Ceará (CE) | 8791688 | 18168.35 |
| 5 | Espírito Santo (ES) | 3833486 | 34065.98 |
| 6 | Goiás (GO) | 7055228 | 31506.97 |
| 7 | Maranhão (MA) | 6775152 | 15027.69 |
| 8 | Mato Grosso (MT) | 3658813 | 50663.19 |
| 9 | Mato Grosso do Sul (MS) | 2756700 | 43649.17 |
| 10 | Minas Gerais (MG) | 20538718 | 32066.73 |
| 11 | Pará (PA) | 8116132 | 24846.62 |
| 12 | Paraíba (PB) | 3974495 | 17402.13 |
| 13 | Paraná (PR) | 11443208 | 42366.71 |
| 14 | Pernambuco (PE) | 9058155 | 20101.38 |
| 15 | Piauí (PI) | 3269200 | 17184.70 |
| 16 | Rio de Janeiro (RJ) | 16054524 | 43407.55 |
| 17 | Rio Grande do Norte (RN) | 3302406 | 20342.11 |
| 18 | Rio Grande do Sul (RS) | 10880506 | 41227.61 |
| 19 | Rondônia (RO) | 1581016 | 28722.45 |
| 20 | Roraima (RR) | 636303 | 25387.77 |
| 21 | Santa Catarina (SC) | 7609601 | 48159.24 |
| 22 | São Paulo (SP) | 44420459 | 51364.73 |
| 23 | Sergipe (SE) | 2209558 | 19583.07 |
| 24 | Tocantins (TO) | 1511459 | 27448.43 |
estados_vendas = df.groupby('estado_vendedor').agg({'preco': ['count', 'mean']}).preco.reset_index()
estados_vendas = estados_vendas \
.merge(populacao_pib, left_on='estado_vendedor', right_on='estado', how='left') \
.drop(columns='estado').rename(columns={'count': 'numero_vendas', 'mean': 'ticket_medio'})
estados_vendas
| estado_vendedor | numero_vendas | ticket_medio | populacao | pib_per_capita | |
|---|---|---|---|---|---|
| 0 | Acre (AC) | 29 | 93106.525083 | 830026 | 18420.26 |
| 1 | Alagoas (AL) | 125 | 129906.553416 | 3127511 | 18857.69 |
| 2 | Amazonas (AM) | 51 | 85051.223887 | 3941175 | 27572.96 |
| 3 | Bahia (BA) | 604 | 129285.733262 | 14136417 | 20449.29 |
| 4 | Ceará (CE) | 69 | 102755.663320 | 8791688 | 18168.35 |
| 5 | Espírito Santo (ES) | 21 | 96534.373882 | 3833486 | 34065.98 |
| 6 | Goiás (GO) | 789 | 153416.087865 | 7055228 | 31506.97 |
| 7 | Maranhão (MA) | 7 | 121041.689127 | 6775152 | 15027.69 |
| 8 | Mato Grosso (MT) | 33 | 143297.450639 | 3658813 | 50663.19 |
| 9 | Mato Grosso do Sul (MS) | 35 | 113270.313388 | 2756700 | 43649.17 |
| 10 | Minas Gerais (MG) | 1775 | 134881.940394 | 20538718 | 32066.73 |
| 11 | Paraná (PR) | 2526 | 145463.002810 | 11443208 | 42366.71 |
| 12 | Paraíba (PB) | 108 | 94476.479022 | 3974495 | 17402.13 |
| 13 | Pará (PA) | 74 | 121008.818768 | 8116132 | 24846.62 |
| 14 | Pernambuco (PE) | 318 | 117126.488389 | 9058155 | 20101.38 |
| 15 | Piauí (PI) | 6 | 177119.450853 | 3269200 | 17184.70 |
| 16 | Rio Grande do Norte (RN) | 90 | 115937.074313 | 3302406 | 20342.11 |
| 17 | Rio Grande do Sul (RS) | 1646 | 141426.402437 | 10880506 | 41227.61 |
| 18 | Rio de Janeiro (RJ) | 2548 | 134959.822564 | 16054524 | 43407.55 |
| 19 | Rondônia (RO) | 4 | 118363.820745 | 1581016 | 28722.45 |
| 20 | Roraima (RR) | 2 | 63613.691193 | 636303 | 25387.77 |
| 21 | Santa Catarina (SC) | 2302 | 134442.621114 | 7609601 | 48159.24 |
| 22 | Sergipe (SE) | 24 | 218926.355581 | 2209558 | 19583.07 |
| 23 | São Paulo (SP) | 16378 | 129756.692797 | 44420459 | 51364.73 |
| 24 | Tocantins (TO) | 20 | 119591.290164 | 1511459 | 27448.43 |
sns.heatmap(estados_vendas.corr(numeric_only=True), annot=True, cmap=sns.diverging_palette(20, 220, n=200), vmin=-1)
plt.show()
Pelo gráfico acima, o número de vendas está fortemente (e positivamente) correlacionado com a população do estado, enquanto que o ticket médio apresenta correlação positiva mais fraca, tanto para população quanto para o PIB per capita.
O conjunto de dados parece apresentar inconsistências, principalmente nas colunas versao, cambio e tipo. Essas inconsistências são percebidas porque a descrição das versões dos veículos não condiz com as demais features. Além disso, esperava-se que as features ano_de_fabricacao e ano_modelo estivessem com no máximo um ano de diferença entre elas, o que não foi observado para os dados apresentados.
Não existe correlação forte entre as variáveis e o target preço. O maior valor encontrado foi uma correlação negativa com o hodômetro, de 0.36.
Os melhores estados para se vender um carro de marca popular são Sergipe, Goiás e Piauí, a depender do critério adotada para se definir uma "marca popular".
Os melhores estados para se comprar uma picape automática foram a Paraíba e o Rio de Janeiro.
Pará e Minas gerais foram os melhores estados para se comprar um veículo com garantia de fábrica.
Das hipóteses elaboradas, notou-se que:
Os vendedores PJ apresentaram comportamento diferenciado com relação aos vendedores PF. Apenas vendedores PJ fazem delivery, e também são os únicos que possuem veículos trocados anteriormente. Todos os vendedores PJ aceitam trocas. Em geral, vendedores PJ anunciam com mais fotos do veículo, não pagam IPVA, não realizam revisões nas concessionárias, não estão com as revisões em dia e não apresentam garantia de fábrica;
O pagamento do IPVA não está ligado com a alíquota do estado;
O número de vendas está fortemente correlacionado à população de cada estado. O ticket médio apresenta correlações menores, tanto para o PIB per capita quanto para a população do estado.